meta-log-db
Version:
Native database package for Meta-Log (ProLog, DataLog, R5RS)
209 lines (174 loc) • 6.49 kB
text/typescript
import { ShaclValidator } from '../shacl/validator.js';
import { TurtleParser } from '../shacl/turtle-parser.js';
import { RdfTriple } from '../types/index.js';
describe('TurtleParser', () => {
describe('Basic parsing', () => {
test('should parse simple triple', () => {
const turtle = `
<http://example.org/node1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Node> .
`;
const triples = TurtleParser.parse(turtle);
expect(triples).toHaveLength(1);
expect(triples[0].subject).toContain('node1');
expect(triples[0].predicate).toContain('type');
expect(triples[0].object).toContain('Node');
});
test('should parse multiple triples', () => {
const turtle = `
<http://example.org/node1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Node> .
<http://example.org/node2> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Node> .
`;
const triples = TurtleParser.parse(turtle);
expect(triples).toHaveLength(2);
});
test('should parse literal values', () => {
const turtle = `
<http://example.org/node1> <http://www.w3.org/2000/01/rdf-schema#label> "Node 1" .
`;
const triples = TurtleParser.parse(turtle);
expect(triples).toHaveLength(1);
const obj = triples[0].object;
if (typeof obj !== 'string') {
expect(obj.value).toBe('Node 1');
}
});
test('should parse typed literals', () => {
const turtle = `
<http://example.org/node1> <http://example.org/count> "10"^^<http://www.w3.org/2001/XMLSchema#integer> .
`;
const triples = TurtleParser.parse(turtle);
expect(triples).toHaveLength(1);
const obj = triples[0].object;
if (typeof obj !== 'string') {
expect(obj.datatype).toBeDefined();
}
});
});
describe('Grouping by subject', () => {
test('should group triples by subject', () => {
const turtle = `
<http://example.org/node1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Node> .
<http://example.org/node1> <http://www.w3.org/2000/01/rdf-schema#label> "Node 1" .
<http://example.org/node2> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Node> .
`;
const triples = TurtleParser.parse(turtle);
const grouped = TurtleParser.groupBySubject(triples);
expect(grouped.size).toBe(2);
expect(grouped.get('http://example.org/node1')).toHaveLength(2);
expect(grouped.get('http://example.org/node2')).toHaveLength(1);
});
});
});
describe('ShaclValidator', () => {
const createTestTriples = (): RdfTriple[] => [
{
subject: 'http://example.org/node1',
predicate: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
object: 'http://example.org/Node'
},
{
subject: 'http://example.org/node1',
predicate: 'http://www.w3.org/2000/01/rdf-schema#label',
object: 'Node 1'
}
];
describe('Shape loading', () => {
test('should load shapes from Turtle file', async () => {
const validator = new ShaclValidator();
// Create test shape file
const fs = require('fs');
const path = require('path');
const testFile = path.join(__dirname, '../../test-shapes.ttl');
const turtle = `
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix ex: <http://example.org/> .
ex:NodeShape
a sh:NodeShape ;
sh:targetClass ex:Node ;
sh:property [
sh:path rdfs:label ;
sh:minCount 1
] .
`;
fs.writeFileSync(testFile, turtle);
try {
const shapes = await validator.loadShapes(testFile);
expect(shapes).toBeDefined();
expect(Object.keys(shapes).length).toBeGreaterThan(0);
} finally {
if (fs.existsSync(testFile)) {
fs.unlinkSync(testFile);
}
}
});
test('should fallback to simple parser on error', async () => {
const validator = new ShaclValidator();
// Invalid Turtle
const fs = require('fs');
const path = require('path');
const testFile = path.join(__dirname, '../../test-invalid.ttl');
fs.writeFileSync(testFile, 'invalid turtle content');
try {
const shapes = await validator.loadShapes(testFile);
// Should not throw, uses fallback parser
expect(shapes).toBeDefined();
} finally {
if (fs.existsSync(testFile)) {
fs.unlinkSync(testFile);
}
}
});
});
describe('Validation', () => {
test('should validate triples against shapes', async () => {
const validator = new ShaclValidator();
const triples = createTestTriples();
const shapes = {
'http://example.org/NodeShape': {
targetClass: 'http://example.org/Node',
properties: [
{
path: 'http://www.w3.org/2000/01/rdf-schema#label',
minCount: 1
}
],
constraints: []
}
};
const report = await validator.validate(shapes, triples);
expect(report).toBeDefined();
expect(report.conforms).toBeDefined();
expect(Array.isArray(report.violations)).toBe(true);
});
test('should detect minCount violations', async () => {
const validator = new ShaclValidator();
const triples: RdfTriple[] = [
{
subject: 'http://example.org/node1',
predicate: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
object: 'http://example.org/Node'
}
// Missing required label
];
const shapes = {
'http://example.org/NodeShape': {
targetClass: 'http://example.org/Node',
properties: [
{
path: 'http://www.w3.org/2000/01/rdf-schema#label',
minCount: 1
}
],
constraints: []
}
};
const report = await validator.validate(shapes, triples);
// Report should exist and have violations array
expect(report).toBeDefined();
expect(Array.isArray(report.violations)).toBe(true);
// May or may not conform depending on validation logic
expect(typeof report.conforms).toBe('boolean');
});
});
});