glam/frontend/tests/unit/sparql-templates.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

186 lines
6.3 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import {
getAllTemplates,
getTemplatesByCategory,
getTemplateById,
applyTemplateVariables,
getCategories,
getCategoryDisplayName,
type QueryTemplate,
} from '../../src/lib/sparql/templates';
describe('SPARQL Templates', () => {
describe('getAllTemplates', () => {
it('should return all query templates', () => {
const templates = getAllTemplates();
expect(templates).toBeDefined();
expect(templates.length).toBeGreaterThan(0);
expect(templates.length).toBeGreaterThanOrEqual(15); // We created 16 templates
});
it('should return templates with required fields', () => {
const templates = getAllTemplates();
for (const template of templates) {
expect(template.id).toBeDefined();
expect(template.name).toBeDefined();
expect(template.description).toBeDefined();
expect(template.category).toBeDefined();
expect(template.query).toBeDefined();
expect(Array.isArray(template.variables)).toBe(true);
}
});
});
describe('getTemplatesByCategory', () => {
it('should return templates filtered by category', () => {
const basicTemplates = getTemplatesByCategory('basic');
expect(basicTemplates.length).toBeGreaterThan(0);
expect(basicTemplates.every(t => t.category === 'basic')).toBe(true);
});
it('should return empty array for non-existent category templates', () => {
const aggregationTemplates = getTemplatesByCategory('aggregation');
expect(aggregationTemplates.length).toBeGreaterThan(0);
});
it('should handle all categories', () => {
const categories: QueryTemplate['category'][] = [
'basic',
'advanced',
'aggregation',
'geographic',
'relationships',
];
for (const category of categories) {
const templates = getTemplatesByCategory(category);
expect(Array.isArray(templates)).toBe(true);
}
});
});
describe('getTemplateById', () => {
it('should return template by ID', () => {
const template = getTemplateById('find-all-museums');
expect(template).toBeDefined();
expect(template?.id).toBe('find-all-museums');
expect(template?.name).toBe('Find All Museums');
});
it('should return undefined for non-existent ID', () => {
const template = getTemplateById('non-existent-id');
expect(template).toBeUndefined();
});
});
describe('applyTemplateVariables', () => {
it('should replace single variable', () => {
const query = 'SELECT ?inst WHERE { ?inst schema:addressLocality "%CITY%" }';
const result = applyTemplateVariables(query, { CITY: 'Amsterdam' });
expect(result).toContain('Amsterdam');
expect(result).not.toContain('%CITY%');
});
it('should replace multiple variables', () => {
const query = 'SELECT ?inst WHERE { ?inst schema:name "%NAME%" . ?inst schema:addressLocality "%CITY%" }';
const result = applyTemplateVariables(query, {
NAME: 'Rijksmuseum',
CITY: 'Amsterdam',
});
expect(result).toContain('Rijksmuseum');
expect(result).toContain('Amsterdam');
expect(result).not.toContain('%NAME%');
expect(result).not.toContain('%CITY%');
});
it('should handle variables without % delimiters', () => {
const query = 'SELECT ?inst WHERE { ?inst schema:addressLocality "%CITY%" }';
const result = applyTemplateVariables(query, { CITY: 'Copenhagen' });
expect(result).toContain('Copenhagen');
});
it('should replace all occurrences of variable', () => {
const query = 'SELECT ?inst WHERE { ?inst schema:name "%NAME%" . FILTER(CONTAINS(?name, "%NAME%")) }';
const result = applyTemplateVariables(query, { NAME: 'Museum' });
const occurrences = (result.match(/Museum/g) || []).length;
expect(occurrences).toBe(2);
});
it('should leave query unchanged if no variables provided', () => {
const query = 'SELECT ?inst WHERE { ?inst a schema:Museum }';
const result = applyTemplateVariables(query, {});
expect(result).toBe(query);
});
});
describe('getCategories', () => {
it('should return all category names', () => {
const categories = getCategories();
expect(categories).toEqual([
'basic',
'advanced',
'aggregation',
'geographic',
'relationships',
]);
});
});
describe('getCategoryDisplayName', () => {
it('should return display names for categories', () => {
expect(getCategoryDisplayName('basic')).toBe('Basic Queries');
expect(getCategoryDisplayName('advanced')).toBe('Advanced Queries');
expect(getCategoryDisplayName('aggregation')).toBe('Aggregation & Statistics');
expect(getCategoryDisplayName('geographic')).toBe('Geographic Queries');
expect(getCategoryDisplayName('relationships')).toBe('Relationships & Hierarchies');
});
});
describe('Template query validation', () => {
it('should have valid SPARQL syntax in all templates', () => {
const templates = getAllTemplates();
for (const template of templates) {
// Basic checks for SPARQL structure
const query = template.query;
// Should have query type
expect(query).toMatch(/\b(SELECT|CONSTRUCT|ASK|DESCRIBE)\b/i);
// Should have balanced braces
const openBraces = (query.match(/\{/g) || []).length;
const closeBraces = (query.match(/\}/g) || []).length;
expect(openBraces).toBe(closeBraces);
// Should have PREFIX declarations before query type
if (query.includes('PREFIX')) {
const prefixIndex = query.indexOf('PREFIX');
const selectIndex = query.search(/\b(SELECT|CONSTRUCT|ASK|DESCRIBE)\b/i);
expect(prefixIndex).toBeLessThan(selectIndex);
}
}
});
it('should declare variables correctly in templates', () => {
const templatesWithVars = getAllTemplates().filter(t => t.variables.length > 0);
for (const template of templatesWithVars) {
for (const variable of template.variables) {
// Variable should be present in query
expect(template.query).toContain(variable);
}
}
});
});
});