- 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.
202 lines
6.3 KiB
TypeScript
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);
|
|
});
|
|
});
|