import { tap, expect } from '@git.zone/tstest/tapbundle'; import { EInvoice } from '../../../ts/index.js'; import { InvoiceFormat, ValidationLevel } from '../../../ts/interfaces/common.js'; import { CorpusLoader, PerformanceTracker } from '../../helpers/test-utils.js'; import * as path from 'path'; /** * Test ID: CORP-02 * Test Description: ZUGFeRD v1 Corpus Processing * Priority: High * * This test validates processing of all ZUGFeRD v1 format files * from the test corpus, including PDF extraction and XML validation. */ tap.test('CORP-02: ZUGFeRD v1 Corpus Processing - should process all ZUGFeRD v1 files', async (t) => { // Load ZUGFeRD v1 test files const zugferdV1Files = await CorpusLoader.loadCategory('ZUGFERD_V1_CORRECT'); console.log(`Testing ${zugferdV1Files.length} ZUGFeRD v1 files`); const results = { total: zugferdV1Files.length, successful: 0, failed: 0, pdfFiles: 0, xmlFiles: 0, extractionErrors: 0, validationErrors: 0, processingTimes: [] as number[] }; const failures: Array<{ file: string; error: string; type: 'extraction' | 'validation' | 'parse'; }> = []; for (const file of zugferdV1Files) { const isPdf = file.path.toLowerCase().endsWith('.pdf'); const isXml = file.path.toLowerCase().endsWith('.xml'); if (isPdf) results.pdfFiles++; if (isXml) results.xmlFiles++; try { const fileBuffer = await CorpusLoader.loadFile(file.path); // Track performance const { result: invoice, metric } = await PerformanceTracker.track( 'zugferd-v1-processing', async () => { const einvoice = new EInvoice(); if (isPdf) { // Extract XML from PDF await einvoice.fromFile(file.path); } else { // Parse XML directly const xmlString = fileBuffer.toString('utf-8'); await einvoice.fromXmlString(xmlString); } return einvoice; }, { file: file.path, size: file.size, type: isPdf ? 'pdf' : 'xml' } ); results.processingTimes.push(metric.duration); // Validate the invoice try { const validationResult = await invoice.validate(ValidationLevel.EXTENDED); if (validationResult.valid) { results.successful++; t.pass(`✓ ${path.basename(file.path)}: Successfully processed`); // Check ZUGFeRD v1 specific fields if (invoice.metadata?.format === InvoiceFormat.ZUGFERD) { t.pass(` - Correctly identified as ZUGFeRD format`); } if (invoice.metadata?.version?.startsWith('1.')) { t.pass(` - Version ${invoice.metadata.version} detected`); } } else { results.validationErrors++; failures.push({ file: path.basename(file.path), error: validationResult.errors?.[0]?.message || 'Validation failed', type: 'validation' }); t.fail(`✗ ${path.basename(file.path)}: Validation failed`); } } catch (validationError: any) { results.validationErrors++; failures.push({ file: path.basename(file.path), error: validationError.message, type: 'validation' }); } } catch (error: any) { results.failed++; if (isPdf && error.message.includes('extract')) { results.extractionErrors++; failures.push({ file: path.basename(file.path), error: error.message, type: 'extraction' }); } else { failures.push({ file: path.basename(file.path), error: error.message, type: 'parse' }); } t.fail(`✗ ${path.basename(file.path)}: ${error.message}`); } } // Summary report console.log('\n=== ZUGFeRD v1 Corpus Processing Summary ==='); console.log(`Total files: ${results.total}`); console.log(` - PDF files: ${results.pdfFiles}`); console.log(` - XML files: ${results.xmlFiles}`); console.log(`Successful: ${results.successful} (${(results.successful/results.total*100).toFixed(1)}%)`); console.log(`Failed: ${results.failed}`); console.log(` - Extraction errors: ${results.extractionErrors}`); console.log(` - Validation errors: ${results.validationErrors}`); if (failures.length > 0) { console.log('\nFailure Details:'); failures.forEach(f => { console.log(` ${f.file} [${f.type}]: ${f.error}`); }); } // Performance metrics if (results.processingTimes.length > 0) { const avgTime = results.processingTimes.reduce((a, b) => a + b, 0) / results.processingTimes.length; const pdfTimes = results.processingTimes.filter((_, i) => zugferdV1Files[i].path.endsWith('.pdf')); const xmlTimes = results.processingTimes.filter((_, i) => zugferdV1Files[i].path.endsWith('.xml')); console.log('\nPerformance Metrics:'); console.log(` Average processing time: ${avgTime.toFixed(2)}ms`); if (pdfTimes.length > 0) { const avgPdfTime = pdfTimes.reduce((a, b) => a + b, 0) / pdfTimes.length; console.log(` Average PDF processing: ${avgPdfTime.toFixed(2)}ms`); } if (xmlTimes.length > 0) { const avgXmlTime = xmlTimes.reduce((a, b) => a + b, 0) / xmlTimes.length; console.log(` Average XML processing: ${avgXmlTime.toFixed(2)}ms`); } } // Success criteria: at least 80% should pass (ZUGFeRD v1 is legacy) const successRate = results.successful / results.total; expect(successRate).toBeGreaterThan(0.8); }); tap.start();