7c858ba633
Rename product to TTRPG Player (TTRPGPlayer / com.ttrpgplayer.app), use .ttrpg.zip for new saves while keeping .dnd.zip import, accept TTRPG- and DND- license keys on client, and remove sync-update-feed plus CI push to DndGamePlayerUpdates. Co-authored-by: Cursor <cursoragent@cursor.com>
99 lines
2.9 KiB
TypeScript
99 lines
2.9 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import fssync from 'node:fs';
|
|
import fs from 'node:fs/promises';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import test from 'node:test';
|
|
|
|
import { ZipFile } from 'yazl';
|
|
|
|
import { PROJECT_SCHEMA_VERSION } from '../../shared/types';
|
|
|
|
import { readProjectJsonFromZip } from './yauzlProjectZip';
|
|
|
|
void test('readProjectJsonFromZip: sequential reads close yauzl (no EMFILE)', async () => {
|
|
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'dnd-zip-read-'));
|
|
const zipPath = path.join(tmp, 'test.ttrpg.zip');
|
|
const minimal = {
|
|
id: 'p1',
|
|
meta: {
|
|
name: 'n',
|
|
fileBaseName: 'f',
|
|
createdAt: '2020-01-01',
|
|
updatedAt: '2020-01-01',
|
|
createdWithAppVersion: '1',
|
|
appVersion: '1',
|
|
schemaVersion: PROJECT_SCHEMA_VERSION,
|
|
},
|
|
scenes: {},
|
|
assets: {},
|
|
currentSceneId: null,
|
|
currentGraphNodeId: null,
|
|
sceneGraphNodes: [],
|
|
sceneGraphEdges: [],
|
|
};
|
|
|
|
const zipfile = new ZipFile();
|
|
zipfile.addBuffer(Buffer.from(JSON.stringify(minimal), 'utf8'), 'project.json', { compressionLevel: 9 });
|
|
const out = fssync.createWriteStream(zipPath);
|
|
const done = new Promise<void>((resolve, reject) => {
|
|
out.on('close', resolve);
|
|
out.on('error', reject);
|
|
});
|
|
zipfile.outputStream.pipe(out);
|
|
zipfile.end();
|
|
await done;
|
|
|
|
for (let i = 0; i < 150; i += 1) {
|
|
const p = await readProjectJsonFromZip(zipPath);
|
|
assert.equal(p.id, 'p1');
|
|
}
|
|
|
|
await fs.rm(tmp, { recursive: true, force: true });
|
|
});
|
|
|
|
void test('readProjectJsonFromZip: campaignAudios round-trips inside project.json', async () => {
|
|
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'dnd-zip-campaign-'));
|
|
const zipPath = path.join(tmp, 'test.ttrpg.zip');
|
|
const assetId = 'audio_asset_1';
|
|
const minimal = {
|
|
id: 'p1',
|
|
meta: {
|
|
name: 'n',
|
|
fileBaseName: 'f',
|
|
createdAt: '2020-01-01',
|
|
updatedAt: '2020-01-01',
|
|
createdWithAppVersion: '1',
|
|
appVersion: '1',
|
|
schemaVersion: PROJECT_SCHEMA_VERSION,
|
|
},
|
|
scenes: {},
|
|
assets: {},
|
|
campaignAudios: [{ assetId, autoplay: true, loop: false }],
|
|
currentSceneId: null,
|
|
currentGraphNodeId: null,
|
|
sceneGraphNodes: [],
|
|
sceneGraphEdges: [],
|
|
};
|
|
|
|
const zipfile = new ZipFile();
|
|
zipfile.addBuffer(Buffer.from(JSON.stringify(minimal), 'utf8'), 'project.json', { compressionLevel: 9 });
|
|
const out = fssync.createWriteStream(zipPath);
|
|
const done = new Promise<void>((resolve, reject) => {
|
|
out.on('close', resolve);
|
|
out.on('error', reject);
|
|
});
|
|
zipfile.outputStream.pipe(out);
|
|
zipfile.end();
|
|
await done;
|
|
|
|
const p = await readProjectJsonFromZip(zipPath);
|
|
assert.ok(Array.isArray((p as { campaignAudios?: unknown }).campaignAudios));
|
|
assert.deepEqual(
|
|
(p as { campaignAudios: typeof minimal.campaignAudios }).campaignAudios,
|
|
minimal.campaignAudios,
|
|
);
|
|
|
|
await fs.rm(tmp, { recursive: true, force: true });
|
|
});
|