Initial curated chimera source from a8ae5b1db07fb49926c94585e2718e5130330974

This commit is contained in:
Public Source Publisher committed 2026-10-01 01:38:08 +02:00
commit c737a37f71
531 files changed
+119270

No files matched your search

@@ -0,0 +1,81 @@
'use strict';
const assert = require('node:assert/strict');
const test = require('node:test');
const { createGameMoveAdapterService, createMemoryJournalStore, unavailableLiveProvider } = require('../../src/services/game-move-adapter-service');
function provider(overrides = {}) {
const calls = { copies: [], deletes: [] };
const base = {
probe: () => ({ provider: 'simulator', version: '1.0.0', live: false, available: true, capabilities: { copyFirst: true, resume: true, verifyHash: true, gameActiveGuard: true, freeSpaceGuard: true, deleteSource: true } }),
isGameActive: async () => false,
freeBytes: async () => 10_000,
copy: async input => { calls.copies.push(input.offset); input.onProgress(input.totalBytes); return { bytesCopied: input.totalBytes }; },
hashSource: async () => 'abc',
hashDestination: async () => 'abc',
deleteSource: async input => { calls.deletes.push(input); },
...overrides,
};
return { adapter: base, calls };
}
test('successful copy verifies before a separately confirmed source delete', async () => {
const fake = provider();
const service = createGameMoveAdapterService({ provider: fake.adapter, uuid: () => 'journal-1', now: () => 100 });
const verified = await service.start({ titleId: 'PPSA00001', sourceId: 'internal', destinationId: 'm2', totalBytes: 1000, expectedHash: 'abc' });
assert.equal(verified.status, 'verified');
assert.equal(verified.deleteEligible, true);
assert.equal(fake.calls.deletes.length, 0);
await assert.rejects(service.deleteSource('journal-1', 'wrong'), /Exact confirmation/);
const completed = await service.deleteSource('journal-1', 'DELETE SOURCE journal-1');
assert.equal(completed.status, 'completed');
assert.equal(completed.sourceDeleted, true);
assert.equal(fake.calls.deletes.length, 1);
});
test('interrupted copy resumes from journal offset', async () => {
let attempts = 0;
const fake = provider({ copy: async input => {
fake.calls.copies.push(input.offset);
attempts += 1;
if (attempts === 1) { const error = new Error('simulated interruption'); error.bytesCopied = 400; throw error; }
input.onProgress(input.totalBytes); return { bytesCopied: input.totalBytes };
} });
const service = createGameMoveAdapterService({ provider: fake.adapter, journals: createMemoryJournalStore(), uuid: () => 'journal-2' });
const interrupted = await service.start({ titleId: 'PPSA00001', sourceId: 'internal', destinationId: 'usb', totalBytes: 1000 });
assert.equal(interrupted.status, 'interrupted');
assert.equal(interrupted.bytesCopied, 400);
const resumed = await service.resume('journal-2');
assert.equal(resumed.status, 'verified');
assert.deepEqual(fake.calls.copies, [0, 400]);
});
test('hash mismatch never becomes delete eligible', async () => {
const fake = provider({ hashDestination: async () => 'different' });
const service = createGameMoveAdapterService({ provider: fake.adapter, uuid: () => 'journal-3' });
const result = await service.start({ titleId: 'PPSA00001', sourceId: 'internal', destinationId: 'm2', totalBytes: 1000 });
assert.equal(result.status, 'needs_attention');
assert.equal(result.error, 'hash-mismatch');
assert.equal(result.deleteEligible, false);
await assert.rejects(service.deleteSource('journal-3', 'DELETE SOURCE journal-3'), /unavailable until copy verification/);
});
test('guards stop active games and insufficient free space before copying', async () => {
const active = provider({ isGameActive: async () => true });
const activeResult = await createGameMoveAdapterService({ provider: active.adapter }).start({ titleId: 'PPSA00001', sourceId: 'a', destinationId: 'b', totalBytes: 100 });
assert.equal(activeResult.error, 'game-active');
assert.equal(active.calls.copies.length, 0);
const full = provider({ freeBytes: async () => 10 });
const fullResult = await createGameMoveAdapterService({ provider: full.adapter }).start({ titleId: 'PPSA00001', sourceId: 'a', destinationId: 'b', totalBytes: 100 });
assert.equal(fullResult.error, 'insufficient-free-space');
assert.equal(full.calls.copies.length, 0);
});
test('capability mismatch and default live provider are visibly unavailable', async () => {
const unavailable = createGameMoveAdapterService({ provider: unavailableLiveProvider() });
assert.equal(unavailable.probe().available, false);
assert.equal(unavailable.probe().compatible, false);
await assert.rejects(unavailable.start({ titleId: 'PPSA00001', sourceId: 'a', destinationId: 'b', totalBytes: 100 }), /unavailable or capability mismatch/i);
const mismatch = provider({ probe: () => ({ provider: 'old-adapter', version: '0.1', available: true, capabilities: { copyFirst: true } }) });
await assert.rejects(createGameMoveAdapterService({ provider: mismatch.adapter }).start({ titleId: 'PPSA00001', sourceId: 'a', destinationId: 'b', totalBytes: 100 }), /capability mismatch/i);
});