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-05: XRechnung Format Detection - should correctly identify XRechnung invoices', async () => { // Get potential XRechnung test files from UBL corpus const ublFiles = await CorpusLoader.getFiles('UBL_XMLRECHNUNG'); const en16931UblFiles = await CorpusLoader.getFiles('EN16931_UBL_EXAMPLES'); // Filter for files that might be XRechnung (look for specific keywords) const allFiles = [...ublFiles, ...en16931UblFiles]; const xrechnungFiles = allFiles.filter(f => path.basename(f).toLowerCase().includes('xrechnung') || path.basename(f).toLowerCase().includes('xr_') || path.basename(f).toLowerCase().includes('de_') ); console.log(`Testing ${xrechnungFiles.length} potential XRechnung 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 xrechnungFiles.slice(0, 10)) { // Limit to first 10 for testing try { // Read XML content const xmlContent = await fs.readFile(filePath, 'utf-8'); // Track performance of format detection const { result: format } = await PerformanceTracker.track( 'xrechnung-format-detection', async () => { return FormatDetector.detectFormat(xmlContent); }, { file: path.basename(filePath) } ); // Verify it's detected as XRechnung or UBL if (format.toString().toLowerCase().includes('xrechnung') || format.toString().toLowerCase().includes('ubl')) { successCount++; } else { failureCount++; failures.push({ file: path.basename(filePath), error: `Detected as ${format} instead of XRechnung/UBL` }); } } catch (error) { failureCount++; failures.push({ file: path.basename(filePath), error: error.message }); } } // Report results const totalTested = Math.min(xrechnungFiles.length, 10); console.log(`\nXRechnung Format Detection Results:`); console.log(`✓ Success: ${successCount}/${totalTested} (${(successCount/totalTested*100).toFixed(1)}%)`); console.log(`✗ Failed: ${failureCount}/${totalTested} (${(failureCount/totalTested*100).toFixed(1)}%)`); if (failures.length > 0) { console.log(`\nFailures:`); failures.forEach(f => console.log(` - ${f.file}: ${f.error}`)); } // Performance summary const perfSummary = await PerformanceTracker.getSummary('xrechnung-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 reasonable success rate expect(successCount / totalTested).toBeGreaterThan(0.6); }); tap.test('FD-05: XRechnung CustomizationID Detection - should detect XRechnung by CustomizationID', async () => { const xrechnungCustomizations = [ 'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_3.0', 'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.3', 'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.2' ]; const { FormatDetector } = await import('../../../ts/formats/utils/format.detector.js'); for (const customization of xrechnungCustomizations) { const testXml = ` ${customization} urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 XR-001 `; const { result: format } = await PerformanceTracker.track( 'xrechnung-customization-detection', async () => FormatDetector.detectFormat(testXml) ); console.log(`Customization ${customization.split(':').pop()}: Detected as ${format}`); // Should detect as XRechnung or UBL const isXRechnungDetected = format.toString().toLowerCase().includes('xrechnung') || format.toString().toLowerCase().includes('ubl'); expect(isXRechnungDetected).toEqual(true); } }); tap.test('FD-05: XRechnung vs UBL Distinction - should distinguish XRechnung from generic UBL', async () => { const testCases = [ { name: 'XRechnung Invoice', xml: ` urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_3.0 XR-001 `, shouldBeXRechnung: true }, { name: 'Generic UBL Invoice', xml: ` urn:cen.eu:en16931:2017 UBL-001 `, shouldBeXRechnung: false } ]; const { FormatDetector } = await import('../../../ts/formats/utils/format.detector.js'); for (const testCase of testCases) { const { result: format } = await PerformanceTracker.track( 'xrechnung-ubl-distinction', async () => FormatDetector.detectFormat(testCase.xml) ); console.log(`${testCase.name}: Detected as ${format}`); const formatStr = format.toString().toLowerCase(); const isXRechnung = formatStr.includes('xrechnung'); if (testCase.shouldBeXRechnung) { // Should be detected as XRechnung specifically expect(isXRechnung).toEqual(true); } else { // Can be UBL or XRechnung (since XRechnung is UBL-based) const isUBLFamily = formatStr.includes('ubl') || formatStr.includes('xrechnung'); expect(isUBLFamily).toEqual(true); } } }); tap.start();