DNDGamePlayer: Electron редактор сцен, презентация, упаковка electron-builder
Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs/promises';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import test from 'node:test';
|
||||
|
||||
import { PROJECT_SCHEMA_VERSION, type Project } from '../../shared/types';
|
||||
import type { AssetId } from '../../shared/types/ids';
|
||||
|
||||
import { collectReferencedAssetIds, reconcileAssetFiles } from './assetPrune';
|
||||
|
||||
void test('collectReferencedAssetIds: превью, видео и аудио', () => {
|
||||
const p = {
|
||||
scenes: {
|
||||
s1: {
|
||||
previewAssetId: 'pr' as AssetId,
|
||||
media: {
|
||||
videos: ['v1' as AssetId],
|
||||
audios: [{ assetId: 'a1' as AssetId, autoplay: true, loop: true }],
|
||||
},
|
||||
},
|
||||
},
|
||||
} as unknown as Project;
|
||||
const s = collectReferencedAssetIds(p);
|
||||
assert.deepEqual([...s].sort(), ['a1', 'pr', 'v1'].sort());
|
||||
});
|
||||
|
||||
void test('reconcileAssetFiles: снимает осиротевшие assets и удаляет файлы', async () => {
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'dnd-asset-prune-'));
|
||||
const relPath = 'assets/orphan.bin';
|
||||
await fs.mkdir(path.join(tmp, 'assets'), { recursive: true });
|
||||
await fs.writeFile(path.join(tmp, relPath), Buffer.from([1, 2, 3]));
|
||||
|
||||
const asset = {
|
||||
id: 'orph' as AssetId,
|
||||
type: 'audio' as const,
|
||||
mime: 'audio/wav',
|
||||
originalName: 'x.wav',
|
||||
relPath,
|
||||
sha256: 'a',
|
||||
sizeBytes: 3,
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const base = {
|
||||
id: 'p1',
|
||||
meta: {
|
||||
name: 't',
|
||||
fileBaseName: 't',
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
createdWithAppVersion: '1',
|
||||
appVersion: '1',
|
||||
schemaVersion: PROJECT_SCHEMA_VERSION,
|
||||
},
|
||||
currentSceneId: null,
|
||||
currentGraphNodeId: null,
|
||||
sceneGraphNodes: [],
|
||||
sceneGraphEdges: [],
|
||||
} as unknown as Project;
|
||||
|
||||
const prev: Project = {
|
||||
...base,
|
||||
scenes: {},
|
||||
assets: { orphan: asset } as Project['assets'],
|
||||
};
|
||||
const next: Project = {
|
||||
...base,
|
||||
scenes: {},
|
||||
assets: { orphan: asset } as Project['assets'],
|
||||
};
|
||||
|
||||
const out = await reconcileAssetFiles(prev, next, tmp);
|
||||
assert.ok(!('orphan' in out.assets));
|
||||
await assert.rejects(() => fs.stat(path.join(tmp, relPath)));
|
||||
});
|
||||
|
||||
void test('reconcileAssetFiles: удаляет файл при исключении id из assets', async () => {
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'dnd-asset-prune-'));
|
||||
const relPath = 'assets/gone.bin';
|
||||
await fs.mkdir(path.join(tmp, 'assets'), { recursive: true });
|
||||
await fs.writeFile(path.join(tmp, relPath), Buffer.from([9]));
|
||||
|
||||
const asset = {
|
||||
id: 'gone' as AssetId,
|
||||
type: 'audio' as const,
|
||||
mime: 'audio/wav',
|
||||
originalName: 'x.wav',
|
||||
relPath,
|
||||
sha256: 'b',
|
||||
sizeBytes: 1,
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const base = {
|
||||
id: 'p1',
|
||||
meta: {
|
||||
name: 't',
|
||||
fileBaseName: 't',
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
createdWithAppVersion: '1',
|
||||
appVersion: '1',
|
||||
schemaVersion: PROJECT_SCHEMA_VERSION,
|
||||
},
|
||||
scenes: {},
|
||||
currentSceneId: null,
|
||||
currentGraphNodeId: null,
|
||||
sceneGraphNodes: [],
|
||||
sceneGraphEdges: [],
|
||||
} as unknown as Project;
|
||||
|
||||
const prev: Project = { ...base, assets: { gone: asset } as Project['assets'] };
|
||||
const next: Project = { ...base, assets: {} as Project['assets'] };
|
||||
|
||||
const out = await reconcileAssetFiles(prev, next, tmp);
|
||||
assert.deepEqual(out.assets, {});
|
||||
await assert.rejects(() => fs.stat(path.join(tmp, relPath)));
|
||||
});
|
||||
Reference in New Issue
Block a user