165 lines
5.9 KiB
TypeScript
165 lines
5.9 KiB
TypeScript
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
|
import { promises as fs } from 'fs';
|
|
import * as path from 'path';
|
|
import { CorpusLoader } from '../../helpers/corpus.loader.js';
|
|
import { PerformanceTracker } from '../../helpers/performance.tracker.js';
|
|
|
|
tap.test('FD-06: PEPPOL Format Detection - should correctly identify PEPPOL invoices', async () => {
|
|
// Get PEPPOL test files from corpus
|
|
const peppolFiles = await CorpusLoader.getFiles('PEPPOL');
|
|
|
|
console.log(`Testing ${peppolFiles.length} PEPPOL invoice files`);
|
|
|
|
let successCount = 0;
|
|
let failureCount = 0;
|
|
const failures: { file: string; error: string }[] = [];
|
|
|
|
// Import the format detector
|
|
const { FormatDetector } = await import('../../../ts/formats/utils/format.detector.js');
|
|
|
|
for (const filePath of peppolFiles) {
|
|
try {
|
|
// Read XML content
|
|
const xmlContent = await fs.readFile(filePath, 'utf-8');
|
|
|
|
// Track performance of format detection
|
|
const { result: format } = await PerformanceTracker.track(
|
|
'peppol-format-detection',
|
|
async () => {
|
|
return FormatDetector.detectFormat(xmlContent);
|
|
},
|
|
{ file: path.basename(filePath) }
|
|
);
|
|
|
|
// PEPPOL files are typically UBL format
|
|
if (format.toString().toLowerCase().includes('ubl') ||
|
|
format.toString().toLowerCase().includes('xrechnung')) {
|
|
successCount++;
|
|
} else {
|
|
failureCount++;
|
|
failures.push({
|
|
file: path.basename(filePath),
|
|
error: `Detected as ${format} instead of UBL/XRechnung`
|
|
});
|
|
}
|
|
} catch (error) {
|
|
failureCount++;
|
|
failures.push({
|
|
file: path.basename(filePath),
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
// Report results
|
|
console.log(`\nPEPPOL Format Detection Results:`);
|
|
console.log(`✓ Success: ${successCount}/${peppolFiles.length} (${(successCount/peppolFiles.length*100).toFixed(1)}%)`);
|
|
console.log(`✗ Failed: ${failureCount}/${peppolFiles.length} (${(failureCount/peppolFiles.length*100).toFixed(1)}%)`);
|
|
|
|
if (failures.length > 0) {
|
|
console.log(`\nFailures:`);
|
|
failures.slice(0, 5).forEach(f => console.log(` - ${f.file}: ${f.error}`));
|
|
if (failures.length > 5) {
|
|
console.log(` ... and ${failures.length - 5} more`);
|
|
}
|
|
}
|
|
|
|
// Performance summary
|
|
const perfSummary = await PerformanceTracker.getSummary('peppol-format-detection');
|
|
if (perfSummary) {
|
|
console.log(`\nPerformance Summary:`);
|
|
console.log(` Average: ${perfSummary.average.toFixed(2)}ms`);
|
|
console.log(` Min: ${perfSummary.min.toFixed(2)}ms`);
|
|
console.log(` Max: ${perfSummary.max.toFixed(2)}ms`);
|
|
console.log(` P95: ${perfSummary.p95.toFixed(2)}ms`);
|
|
}
|
|
|
|
// Expect high success rate
|
|
expect(successCount / peppolFiles.length).toBeGreaterThan(0.9);
|
|
});
|
|
|
|
tap.test('FD-06: PEPPOL BIS Profile Detection - should detect PEPPOL BIS profiles', async () => {
|
|
const peppolProfiles = [
|
|
'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0',
|
|
'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
|
|
'urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0'
|
|
];
|
|
|
|
const { FormatDetector } = await import('../../../ts/formats/utils/format.detector.js');
|
|
|
|
for (const profile of peppolProfiles) {
|
|
const testXml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
|
|
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
|
|
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
|
|
<cbc:ProfileID>${profile}</cbc:ProfileID>
|
|
<cbc:ID>PEPPOL-001</cbc:ID>
|
|
</Invoice>`;
|
|
|
|
const { result: format } = await PerformanceTracker.track(
|
|
'peppol-profile-detection',
|
|
async () => FormatDetector.detectFormat(testXml)
|
|
);
|
|
|
|
console.log(`Profile ${profile.split(':').pop()}: Detected as ${format}`);
|
|
|
|
// Should detect as UBL or XRechnung (PEPPOL is UBL-based)
|
|
const isUBLFamily = format.toString().toLowerCase().includes('ubl') ||
|
|
format.toString().toLowerCase().includes('xrechnung');
|
|
expect(isUBLFamily).toEqual(true);
|
|
}
|
|
});
|
|
|
|
tap.test('FD-06: PEPPOL Large Invoice Performance - should handle large PEPPOL invoices efficiently', async () => {
|
|
// Get large PEPPOL files
|
|
const peppolFiles = await CorpusLoader.getFiles('PEPPOL');
|
|
const largeFiles = peppolFiles.filter(f => path.basename(f).includes('Large'));
|
|
|
|
if (largeFiles.length === 0) {
|
|
console.log('No large PEPPOL files found, skipping performance test');
|
|
return;
|
|
}
|
|
|
|
console.log(`Testing performance with ${largeFiles.length} large PEPPOL files`);
|
|
|
|
const { FormatDetector } = await import('../../../ts/formats/utils/format.detector.js');
|
|
|
|
for (const filePath of largeFiles) {
|
|
try {
|
|
const xmlContent = await fs.readFile(filePath, 'utf-8');
|
|
const fileSize = xmlContent.length;
|
|
|
|
console.log(`Testing ${path.basename(filePath)} (${Math.round(fileSize/1024)}KB)`);
|
|
|
|
// Test multiple times for accurate measurement
|
|
const times: number[] = [];
|
|
let detectedFormat = '';
|
|
|
|
for (let i = 0; i < 5; i++) {
|
|
const { result: format, metric } = await PerformanceTracker.track(
|
|
'peppol-large-file-detection',
|
|
async () => FormatDetector.detectFormat(xmlContent)
|
|
);
|
|
|
|
times.push(metric.duration);
|
|
detectedFormat = format.toString();
|
|
}
|
|
|
|
const avgTime = times.reduce((a, b) => a + b, 0) / times.length;
|
|
const maxTime = Math.max(...times);
|
|
|
|
console.log(` Format: ${detectedFormat}`);
|
|
console.log(` Average: ${avgTime.toFixed(2)}ms`);
|
|
console.log(` Max: ${maxTime.toFixed(2)}ms`);
|
|
|
|
// Performance assertions
|
|
expect(avgTime).toBeLessThan(50); // Should be under 50ms on average
|
|
expect(maxTime).toBeLessThan(100); // Should never exceed 100ms
|
|
|
|
} catch (error) {
|
|
console.log(` Error: ${error.message}`);
|
|
}
|
|
}
|
|
});
|
|
|
|
tap.start(); |