- 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.
235 lines
7 KiB
TypeScript
235 lines
7 KiB
TypeScript
/**
|
|
* Tests for SPARQL Results Export
|
|
*/
|
|
|
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
import {
|
|
exportToCsv,
|
|
exportToJson,
|
|
exportToJsonLd,
|
|
exportAndDownload,
|
|
} from '../../src/lib/sparql/export';
|
|
import type { SelectResults } from '../../src/lib/sparql/client';
|
|
|
|
describe('SPARQL Export', () => {
|
|
const mockResults: SelectResults = {
|
|
head: { vars: ['subject', 'predicate', 'object'] },
|
|
results: {
|
|
bindings: [
|
|
{
|
|
subject: { type: 'uri', value: 'http://example.org/s1' },
|
|
predicate: { type: 'uri', value: 'http://example.org/p1' },
|
|
object: { type: 'literal', value: 'Object 1' },
|
|
},
|
|
{
|
|
subject: { type: 'uri', value: 'http://example.org/s2' },
|
|
predicate: { type: 'uri', value: 'http://example.org/p2' },
|
|
object: { type: 'literal', value: 'Object 2', 'xml:lang': 'en' },
|
|
},
|
|
{
|
|
subject: { type: 'bnode', value: '_:b1' },
|
|
predicate: { type: 'uri', value: 'http://example.org/p3' },
|
|
object: {
|
|
type: 'literal',
|
|
value: '42',
|
|
datatype: 'http://www.w3.org/2001/XMLSchema#integer',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
};
|
|
|
|
describe('exportToCsv', () => {
|
|
it('should export results to CSV format', () => {
|
|
const csv = exportToCsv(mockResults);
|
|
|
|
expect(csv).toContain('subject,predicate,object');
|
|
expect(csv).toContain('http://example.org/s1');
|
|
expect(csv).toContain('Object 1');
|
|
});
|
|
|
|
it('should escape CSV values with commas', () => {
|
|
const results: SelectResults = {
|
|
head: { vars: ['text'] },
|
|
results: {
|
|
bindings: [{ text: { type: 'literal', value: 'value, with, commas' } }],
|
|
},
|
|
};
|
|
|
|
const csv = exportToCsv(results);
|
|
expect(csv).toContain('"value, with, commas"');
|
|
});
|
|
|
|
it('should escape CSV values with quotes', () => {
|
|
const results: SelectResults = {
|
|
head: { vars: ['text'] },
|
|
results: {
|
|
bindings: [{ text: { type: 'literal', value: 'value "with" quotes' } }],
|
|
},
|
|
};
|
|
|
|
const csv = exportToCsv(results);
|
|
expect(csv).toContain('"value ""with"" quotes"');
|
|
});
|
|
|
|
it('should handle empty results', () => {
|
|
const results: SelectResults = {
|
|
head: { vars: ['a', 'b'] },
|
|
results: { bindings: [] },
|
|
};
|
|
|
|
const csv = exportToCsv(results);
|
|
expect(csv).toBe('');
|
|
});
|
|
|
|
it('should include language tags in CSV', () => {
|
|
const csv = exportToCsv(mockResults);
|
|
expect(csv).toContain('Object 2@en');
|
|
});
|
|
|
|
it('should include datatypes in CSV', () => {
|
|
const csv = exportToCsv(mockResults);
|
|
expect(csv).toContain('42^^http://www.w3.org/2001/XMLSchema#integer');
|
|
});
|
|
|
|
it('should handle missing values', () => {
|
|
const results: SelectResults = {
|
|
head: { vars: ['a', 'b', 'c'] },
|
|
results: {
|
|
bindings: [
|
|
{ a: { type: 'literal', value: 'A' } },
|
|
// b and c are missing
|
|
],
|
|
},
|
|
};
|
|
|
|
const csv = exportToCsv(results);
|
|
expect(csv).toContain('A,,');
|
|
});
|
|
});
|
|
|
|
describe('exportToJson', () => {
|
|
it('should export results to JSON format', () => {
|
|
const json = exportToJson(mockResults);
|
|
const parsed = JSON.parse(json);
|
|
|
|
expect(parsed).toHaveProperty('head');
|
|
expect(parsed).toHaveProperty('results');
|
|
expect(parsed.head.vars).toEqual(['subject', 'predicate', 'object']);
|
|
expect(parsed.results.bindings).toHaveLength(3);
|
|
});
|
|
|
|
it('should format JSON with indentation', () => {
|
|
const json = exportToJson(mockResults);
|
|
expect(json).toContain('\n ');
|
|
});
|
|
});
|
|
|
|
describe('exportToJsonLd', () => {
|
|
it('should export results to JSON-LD format', () => {
|
|
const jsonld = exportToJsonLd(mockResults);
|
|
const parsed = JSON.parse(jsonld);
|
|
|
|
expect(parsed).toHaveProperty('@context');
|
|
expect(parsed).toHaveProperty('@graph');
|
|
expect(parsed['@graph']).toHaveLength(3);
|
|
});
|
|
|
|
it('should convert URIs to @id', () => {
|
|
const jsonld = exportToJsonLd(mockResults);
|
|
const parsed = JSON.parse(jsonld);
|
|
|
|
const firstResult = parsed['@graph'][0];
|
|
expect(firstResult.subject).toHaveProperty('@id');
|
|
expect(firstResult.subject['@id']).toBe('http://example.org/s1');
|
|
});
|
|
|
|
it('should convert literals to @value', () => {
|
|
const jsonld = exportToJsonLd(mockResults);
|
|
const parsed = JSON.parse(jsonld);
|
|
|
|
const firstResult = parsed['@graph'][0];
|
|
expect(firstResult.object).toHaveProperty('@value');
|
|
expect(firstResult.object['@value']).toBe('Object 1');
|
|
});
|
|
|
|
it('should include language tags', () => {
|
|
const jsonld = exportToJsonLd(mockResults);
|
|
const parsed = JSON.parse(jsonld);
|
|
|
|
const secondResult = parsed['@graph'][1];
|
|
expect(secondResult.object).toHaveProperty('@language');
|
|
expect(secondResult.object['@language']).toBe('en');
|
|
});
|
|
|
|
it('should include datatypes', () => {
|
|
const jsonld = exportToJsonLd(mockResults);
|
|
const parsed = JSON.parse(jsonld);
|
|
|
|
const thirdResult = parsed['@graph'][2];
|
|
expect(thirdResult.object).toHaveProperty('@type');
|
|
expect(thirdResult.object['@type']).toBe(
|
|
'http://www.w3.org/2001/XMLSchema#integer'
|
|
);
|
|
});
|
|
|
|
it('should assign blank node IDs to results', () => {
|
|
const jsonld = exportToJsonLd(mockResults);
|
|
const parsed = JSON.parse(jsonld);
|
|
|
|
expect(parsed['@graph'][0]['@id']).toMatch(/_:result\d+/);
|
|
expect(parsed['@graph'][0]['@type']).toBe('SparqlResult');
|
|
});
|
|
});
|
|
|
|
describe('exportAndDownload', () => {
|
|
let createElementSpy: any;
|
|
let linkElement: any;
|
|
|
|
beforeEach(() => {
|
|
linkElement = {
|
|
href: '',
|
|
download: '',
|
|
click: vi.fn(),
|
|
};
|
|
|
|
createElementSpy = vi.spyOn(document, 'createElement').mockReturnValue(linkElement);
|
|
|
|
global.URL.createObjectURL = vi.fn(() => 'blob:mock-url');
|
|
global.URL.revokeObjectURL = vi.fn();
|
|
global.Blob = vi.fn() as any;
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it('should download CSV file', () => {
|
|
exportAndDownload(mockResults, 'csv', 'test-results');
|
|
|
|
expect(linkElement.download).toBe('test-results.csv');
|
|
expect(linkElement.click).toHaveBeenCalled();
|
|
expect(global.URL.revokeObjectURL).toHaveBeenCalledWith('blob:mock-url');
|
|
});
|
|
|
|
it('should download JSON file', () => {
|
|
exportAndDownload(mockResults, 'json', 'test-results');
|
|
|
|
expect(linkElement.download).toBe('test-results.json');
|
|
expect(linkElement.click).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should download JSON-LD file', () => {
|
|
exportAndDownload(mockResults, 'jsonld', 'test-results');
|
|
|
|
expect(linkElement.download).toBe('test-results.jsonld');
|
|
expect(linkElement.click).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should use default filename if not provided', () => {
|
|
exportAndDownload(mockResults, 'csv');
|
|
|
|
expect(linkElement.download).toBe('sparql-results.csv');
|
|
});
|
|
});
|
|
});
|