Files

108 lines
4.6 KiB
JavaScript
Raw Permalink Normal View History

/**
* SnapshotBinary round-trip tests.
*
* Verifies:
* - serialize/deserialize preserves nodes and relations
* - Deserialized snapshots are marked _snapshotReadOnly
* - UTF-8 keys survive round-trip
* - Relation configs survive round-trip
*
* Run: node --test --test-force-exit lib/tests/property-based/snapshot-binary.test.js
*/
import { Arbiter } from '../../src/core/Arbiter.js';
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
function createArbiterFactory() {
return () => new Arbiter({ fastConstructionMode: true, enableInference: false });
}
async function loadSnapshotModule() {
return import('../../src/core/SnapshotBinary.js');
}
describe('SnapshotBinary — Round-Trip', () => {
it('serialize and deserialize preserves nodes and relations', async () => {
const { serializeArbiterSnapshot, deserializeArbiterSnapshot } = await loadSnapshotModule();
const original = new Arbiter({ fastConstructionMode: true, enableInference: false });
original.addNode('user:alice', 'user');
original.addNode('project:secret', 'project');
original.addRelation('user:alice', 'can_read', 'project:secret', { possibility: 0.9, value: 100 });
original.setRelationConfig('can_read', { type: 'direct' });
original.enableCondensedSnapshot();
const buffer = serializeArbiterSnapshot(original);
assert.ok(buffer instanceof ArrayBuffer);
assert.ok(buffer.byteLength > 0);
const restored = deserializeArbiterSnapshot(buffer, createArbiterFactory());
assert.ok(restored.nodeIdByKey.has('user:alice'));
assert.ok(restored.nodeIdByKey.has('project:secret'));
const nodes = [...restored.nodes.values()].filter(Boolean);
assert.ok(nodes.length >= 2);
});
it('deserialized snapshot is marked read-only', async () => {
const { serializeArbiterSnapshot, deserializeArbiterSnapshot } = await loadSnapshotModule();
const original = new Arbiter({ fastConstructionMode: true, enableInference: false });
original.addNode('user:alice', 'user');
original.addNode('project:secret', 'project');
original.addRelation('user:alice', 'can_read', 'project:secret', { possibility: 0.9 });
original.enableCondensedSnapshot();
const buffer = serializeArbiterSnapshot(original);
const restored = deserializeArbiterSnapshot(buffer, createArbiterFactory());
assert.strictEqual(restored._snapshotReadOnly, true);
assert.strictEqual(restored.snapshotEnabled, true);
assert.ok(restored.snapshotGraph);
});
it('UTF-8 keys survive round-trip', async () => {
const { serializeArbiterSnapshot, deserializeArbiterSnapshot } = await loadSnapshotModule();
const original = new Arbiter({ fastConstructionMode: true, enableInference: false });
original.addNode('user:alice', 'user');
original.addNode('project:résumé', 'project');
original.addRelation('user:alice', 'can_read', 'project:résumé', { possibility: 0.9 });
original.setRelationConfig('can_read', { type: 'direct' });
original.enableCondensedSnapshot();
const buffer = serializeArbiterSnapshot(original);
const restored = deserializeArbiterSnapshot(buffer, createArbiterFactory());
assert.ok(restored.nodeIdByKey.has('project:résumé'));
assert.strictEqual(restored.relationConfigs.has('can_read'), true);
});
it('relation configs survive round-trip', async () => {
const { serializeArbiterSnapshot, deserializeArbiterSnapshot } = await loadSnapshotModule();
const original = new Arbiter({ fastConstructionMode: true, enableInference: false });
original.addNode('user:alice', 'user');
original.addNode('project:secret', 'project');
original.addRelation('user:alice', 'can_access', 'project:secret', {
possibility: 0.8,
value: 42,
reliability: 0.95
});
original.setRelationConfig('can_access', { type: 'chain', steps: [{ relation: 'parent', direction: 'out' }] });
original.setRelationConfig('can_read', { type: 'direct', minPossibility: 0.5 });
original.enableCondensedSnapshot();
const buffer = serializeArbiterSnapshot(original);
const restored = deserializeArbiterSnapshot(buffer, createArbiterFactory());
const accessConfig = restored.relationConfigs.get('can_access');
assert.strictEqual(accessConfig && accessConfig.type, 'chain');
assert.deepStrictEqual(accessConfig && accessConfig.steps, [{ relation: 'parent', direction: 'out' }]);
const readConfig = restored.relationConfigs.get('can_read');
assert.strictEqual(readConfig && readConfig.type, 'direct');
assert.strictEqual(readConfig && readConfig.minPossibility, 0.5);
});
});