import { tap, expect } from '@git.zone/tstest/tapbundle'; import { SchematronValidator, HybridValidator } from '../ts/formats/validation/schematron.validator.js'; import { SchematronDownloader } from '../ts/formats/validation/schematron.downloader.js'; import { SchematronWorkerPool } from '../ts/formats/validation/schematron.worker.js'; tap.test('Schematron Infrastructure - should initialize correctly', async () => { const validator = new SchematronValidator(); expect(validator).toBeInstanceOf(SchematronValidator); expect(validator.hasRules()).toBeFalse(); }); tap.test('Schematron Infrastructure - should load Schematron rules', async () => { const validator = new SchematronValidator(); // Load a simple test Schematron const testSchematron = ` Invoice must have an ID `; await validator.loadSchematron(testSchematron, false); expect(validator.hasRules()).toBeTrue(); }); tap.test('Schematron Infrastructure - should detect phases', async () => { const validator = new SchematronValidator(); const schematronWithPhases = ` Invoice must have ID `; await validator.loadSchematron(schematronWithPhases, false); const phases = await validator.getPhases(); expect(phases).toContain('basic'); expect(phases).toContain('extended'); }); tap.test('Schematron Downloader - should initialize', async () => { const downloader = new SchematronDownloader('.nogit/schematron-test'); await downloader.initialize(); // Check that sources are defined expect(downloader).toBeInstanceOf(SchematronDownloader); }); tap.test('Schematron Downloader - should list available sources', async () => { const { SCHEMATRON_SOURCES } = await import('../ts/formats/validation/schematron.downloader.js'); // Check EN16931 sources expect(SCHEMATRON_SOURCES.EN16931).toBeDefined(); expect(SCHEMATRON_SOURCES.EN16931.length).toBeGreaterThan(0); const en16931Ubl = SCHEMATRON_SOURCES.EN16931.find(s => s.format === 'UBL'); expect(en16931Ubl).toBeDefined(); expect(en16931Ubl?.name).toEqual('EN16931-UBL'); // Check PEPPOL sources expect(SCHEMATRON_SOURCES.PEPPOL).toBeDefined(); expect(SCHEMATRON_SOURCES.PEPPOL.length).toBeGreaterThan(0); // Check XRechnung sources expect(SCHEMATRON_SOURCES.XRECHNUNG).toBeDefined(); expect(SCHEMATRON_SOURCES.XRECHNUNG.length).toBeGreaterThan(0); }); tap.test('Hybrid Validator - should combine validators', async () => { const schematronValidator = new SchematronValidator(); const hybrid = new HybridValidator(schematronValidator); // Add a mock TypeScript validator const mockTSValidator = { validate: (xml: string) => [{ ruleId: 'TS-TEST-01', severity: 'error' as const, message: 'Test error from TS validator', btReference: undefined, bgReference: undefined }] }; hybrid.addTSValidator(mockTSValidator); // Test validation (will only run TS validator since no Schematron loaded) const results = await hybrid.validate(''); expect(results.length).toEqual(1); expect(results[0].ruleId).toEqual('TS-TEST-01'); }); tap.test('Schematron Worker Pool - should initialize', async () => { const pool = new SchematronWorkerPool(2); // Test pool stats const stats = pool.getStats(); expect(stats.totalWorkers).toEqual(0); // Not initialized yet expect(stats.queuedTasks).toEqual(0); // Note: Full worker pool test would require actual worker thread setup // which may not work in all test environments }); tap.test('Schematron Validator - SVRL parsing', async () => { const validator = new SchematronValidator(); // Test SVRL output parsing const testSVRL = ` [BR-01] Invoice must have exactly one ID Currency is EUR `; // This would test the SVRL parsing logic // The actual implementation would parse this and return ValidationResult[] expect(testSVRL).toContain('failed-assert'); expect(testSVRL).toContain('BR-01'); }); tap.test('Schematron Integration - should handle missing files gracefully', async () => { const validator = new SchematronValidator(); try { await validator.loadSchematron('non-existent-file.sch', true); expect(true).toBeFalse(); // Should not reach here } catch (error) { expect(error).toBeDefined(); } }); tap.start();