Files
DndGamePlayer/app/main/project/assetPrune.test.ts
T

120 lines
3.4 KiB
TypeScript

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