glam/frontend/tests/unit/graph-utils.test.ts
kempersc 2761857b0d Add scripts for converting OWL/Turtle ontology to Mermaid and PlantUML diagrams
- Implemented `owl_to_mermaid.py` to convert OWL/Turtle files into Mermaid class diagrams.
- Implemented `owl_to_plantuml.py` to convert OWL/Turtle files into PlantUML class diagrams.
- Added two new PlantUML files for custodian multi-aspect diagrams.
2025-11-22 23:01:13 +01:00

202 lines
6.3 KiB
TypeScript

/**
* Tests for Graph Utilities
*/
import { describe, it, expect } from 'vitest';
import {
getNodeColor,
getNodeRadius,
calculateNodeDegree,
getConnectedNodes,
findHubNodes,
filterNodesByType,
getUniqueNodeTypes,
getUniquePredicates,
calculateGraphStats,
formatNodeForExport,
formatLinkForExport,
} from '@/lib/rdf/graph-utils';
import type { GraphNode, GraphLink } from '@/types/rdf';
describe('Graph Utilities - Node Operations', () => {
const sampleNodes: GraphNode[] = [
{ id: 'node1', label: 'Node 1', uri: 'http://example.org/node1', type: 'Record' },
{ id: 'node2', label: 'Node 2', uri: 'http://example.org/node2', type: 'Person' },
{ id: 'node3', label: 'Node 3', uri: 'http://example.org/node3', type: 'Place' },
{ id: 'node4', label: 'Node 4', uri: 'http://example.org/node4', type: 'Record' },
];
const sampleLinks: GraphLink[] = [
{
source: 'node1',
target: 'node2',
predicate: 'author',
value: 1,
isReversed: false,
isBidirectional: false,
},
{
source: 'node1',
target: 'node3',
predicate: 'place',
value: 1,
isReversed: false,
isBidirectional: false,
},
{
source: 'node2',
target: 'node3',
predicate: 'located at',
value: 1,
isReversed: false,
isBidirectional: false,
},
];
it('should get node color by type', () => {
expect(getNodeColor('Record')).toBe('#4A90E2');
expect(getNodeColor('Person')).toBe('#F39C12');
expect(getNodeColor('Place')).toBe('#2ECC71');
});
it('should calculate node radius based on connections', () => {
const radius1 = getNodeRadius(sampleNodes[0], sampleLinks);
const radius2 = getNodeRadius(sampleNodes[1], sampleLinks);
expect(radius1).toBeGreaterThan(8);
expect(radius2).toBeGreaterThan(8);
});
it('should filter nodes by type', () => {
const records = filterNodesByType(sampleNodes, ['Record']);
expect(records).toHaveLength(2);
expect(records.every((n) => n.type === 'Record')).toBe(true);
const people = filterNodesByType(sampleNodes, ['Person']);
expect(people).toHaveLength(1);
});
it('should get unique node types', () => {
const types = getUniqueNodeTypes(sampleNodes);
expect(types).toContain('Record');
expect(types).toContain('Person');
expect(types).toContain('Place');
expect(types).toHaveLength(3);
});
it('should format node for export', () => {
const exported = formatNodeForExport(sampleNodes[0]);
expect(exported).toHaveProperty('id');
expect(exported).toHaveProperty('label');
expect(exported).toHaveProperty('uri');
expect(exported).toHaveProperty('type');
});
});
describe('Graph Utilities - Link Operations', () => {
const sampleLinks: GraphLink[] = [
{
source: 'node1',
target: 'node2',
predicate: 'author',
value: 1,
isReversed: false,
isBidirectional: false,
},
{
source: 'node1',
target: 'node3',
predicate: 'place',
value: 1,
isReversed: false,
isBidirectional: false,
},
{
source: 'node2',
target: 'node3',
predicate: 'author',
value: 1,
isReversed: false,
isBidirectional: false,
},
];
it('should get unique predicates', () => {
const predicates = getUniquePredicates(sampleLinks);
expect(predicates).toContain('author');
expect(predicates).toContain('place');
expect(predicates).toHaveLength(2);
});
it('should format link for export', () => {
const exported = formatLinkForExport(sampleLinks[0]);
expect(exported).toHaveProperty('source');
expect(exported).toHaveProperty('target');
expect(exported).toHaveProperty('predicate');
});
});
describe('Graph Utilities - Node Degree', () => {
const sampleLinks: GraphLink[] = [
{ source: 'node1', target: 'node2', predicate: 'p1', value: 1, isReversed: false, isBidirectional: false },
{ source: 'node1', target: 'node3', predicate: 'p2', value: 1, isReversed: false, isBidirectional: false },
{ source: 'node2', target: 'node3', predicate: 'p3', value: 1, isReversed: false, isBidirectional: false },
{ source: 'node4', target: 'node1', predicate: 'p4', value: 1, isReversed: false, isBidirectional: false },
];
it('should calculate node degree', () => {
const degree1 = calculateNodeDegree('node1', sampleLinks);
expect(degree1.outDegree).toBe(2);
expect(degree1.inDegree).toBe(1);
expect(degree1.totalDegree).toBe(3);
const degree2 = calculateNodeDegree('node2', sampleLinks);
expect(degree2.outDegree).toBe(1);
expect(degree2.inDegree).toBe(1);
expect(degree2.totalDegree).toBe(2);
});
it('should get connected nodes', () => {
const connections = getConnectedNodes('node1', sampleLinks);
expect(connections.outgoing).toContain('node2');
expect(connections.outgoing).toContain('node3');
expect(connections.incoming).toContain('node4');
});
it('should find hub nodes', () => {
const sampleNodes: GraphNode[] = [
{ id: 'node1', label: 'Node 1', uri: 'uri1', type: 'Record' },
{ id: 'node2', label: 'Node 2', uri: 'uri2', type: 'Record' },
{ id: 'node3', label: 'Node 3', uri: 'uri3', type: 'Record' },
{ id: 'node4', label: 'Node 4', uri: 'uri4', type: 'Record' },
];
const hubs = findHubNodes(sampleNodes, sampleLinks, 2);
expect(hubs.length).toBeGreaterThan(0);
});
});
describe('Graph Statistics', () => {
const sampleNodes: GraphNode[] = [
{ id: 'node1', label: 'Node 1', uri: 'uri1', type: 'Record' },
{ id: 'node2', label: 'Node 2', uri: 'uri2', type: 'Person' },
{ id: 'node3', label: 'Node 3', uri: 'uri3', type: 'Record' },
];
const sampleLinks: GraphLink[] = [
{ source: 'node1', target: 'node2', predicate: 'author', value: 1, isReversed: false, isBidirectional: false },
{ source: 'node1', target: 'node3', predicate: 'part of', value: 1, isReversed: false, isBidirectional: false },
];
it('should calculate graph statistics', () => {
const stats = calculateGraphStats(sampleNodes, sampleLinks);
expect(stats.nodeCount).toBe(3);
expect(stats.linkCount).toBe(2);
expect(stats.nodeTypes['Record']).toBe(2);
expect(stats.nodeTypes['Person']).toBe(1);
expect(stats.predicates['author']).toBe(1);
expect(stats.predicates['part of']).toBe(1);
expect(stats.avgDegree).toBeGreaterThan(0);
});
});