import assert from 'node:assert/strict'; import { describe, test } from 'node:test'; import { CondensedGraph } from '../../src/core/CondensedGraph.js'; describe('CondensedGraph (Simplified Succinct Format)', () => { test('basic edge operations', () => { const graph = new CondensedGraph(); graph.addEdge('user:alice', 'owner', 'doc:report'); graph.addEdge('user:bob', 'member', 'group:engineering'); graph.addEdge('user:charlie', 'viewer', 'doc:report'); assert.strictEqual(graph.numEdges, 3); const edges = graph.getOutEdges('user:alice'); assert.strictEqual(edges.length, 1); const edge = graph.getEdge(edges[0]); assert.strictEqual(edge.src, 'user:alice'); assert.strictEqual(edge.dst, 'doc:report'); }); test('find edge by relation', () => { const graph = new CondensedGraph(); graph.addEdge('user:alice', 'owner', 'doc:report'); graph.addEdge('user:bob', 'owner', 'doc:finance'); graph.addEdge('user:alice', 'member', 'group:engineering'); const idx = graph.findEdge('user:alice', graph.getRelationId('owner'), 'doc:report'); assert.ok(idx !== null, 'Should find edge'); const edge = graph.getEdge(idx); assert.strictEqual(edge.src, 'user:alice'); assert.strictEqual(edge.dst, 'doc:report'); }); test('multiple edges from same source', () => { const graph = new CondensedGraph(); graph.addEdge('user:alice', 'owner', 'doc:report'); graph.addEdge('user:alice', 'member', 'group:engineering'); graph.addEdge('user:alice', 'viewer', 'doc:report'); const edges = graph.getOutEdges('user:alice'); assert.strictEqual(edges.length, 3); }); test('remove edge', () => { const graph = new CondensedGraph(); graph.addEdge('user:alice', 'owner', 'doc:report'); graph.addEdge('user:alice', 'member', 'group:engineering'); const initialEdges = graph.getOutEdges('user:alice'); assert.strictEqual(initialEdges.length, 2); const idx = graph.findEdge('user:alice', graph.getRelationId('member'), 'group:engineering'); graph.removeEdge(idx); const afterEdges = graph.getOutEdges('user:alice'); assert.strictEqual(afterEdges.length, 1); }); test('degree tracking', () => { const graph = new CondensedGraph(); graph.addEdge('user:alice', 'owner', 'doc:report'); graph.addEdge('user:alice', 'member', 'group:engineering'); graph.addEdge('user:alice', 'viewer', 'doc:report'); assert.strictEqual(graph.getDegree('user:alice'), 3); }); test('edge existence check', () => { const graph = new CondensedGraph(); graph.addEdge('user:alice', 'owner', 'doc:report'); graph.addEdge('user:bob', 'member', 'group:engineering'); assert.ok(graph.hasEdge('user:alice', graph.getRelationId('owner'), 'doc:report')); assert.ok(!graph.hasEdge('user:charlie', graph.getRelationId('owner'), 'doc:report')); }); test('iterate all edges', () => { const graph = new CondensedGraph(); for (let i = 0; i < 10; i++) { graph.addEdge(`user:${i}`, 'relation', `user:${i + 1}`); } let count = 0; graph.forEachOutEdge('user:5', (edge) => { count++; }); assert.strictEqual(count, 1); }); test('memory efficiency', () => { const graph = new CondensedGraph(); const numEdges = 50000; const startMem = process.memoryUsage().heapUsed; for (let i = 0; i < numEdges; i++) { graph.addEdge(`user:${i % 100}`, 'relation', `user:${(i + 1) % 1000}`); } const endMem = process.memoryUsage().heapUsed; const memDelta = endMem - startMem; const stats = graph.getStats(); console.log('Memory efficiency test:'); console.log(' - Edges:', numEdges); console.log(' - Stats:', stats); console.log(' - Heap delta:', (memDelta / 1024 / 1024).toFixed(2), 'MB'); console.log(' - Bytes per edge:', (memDelta / numEdges).toFixed(2)); assert.strictEqual(graph.numEdges, numEdges); assert.ok(memDelta < 30 * 1024 * 1024, 'Memory usage should be reasonable (< 30MB)'); }); });