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('VAL-01: XML Syntax Validation - should validate XML syntax of invoice files', async () => { // Get XML test files from various categories const ciiFiles = await CorpusLoader.getFiles('CII_XMLRECHNUNG'); const ublFiles = await CorpusLoader.getFiles('UBL_XMLRECHNUNG'); const en16931CiiFiles = await CorpusLoader.getFiles('EN16931_CII'); // Combine and limit for testing const allXmlFiles = [...ciiFiles, ...ublFiles, ...en16931CiiFiles] .filter(f => f.endsWith('.xml')) .slice(0, 20); // Test first 20 files console.log(`Testing XML syntax validation on ${allXmlFiles.length} files`); let validCount = 0; let invalidCount = 0; const errors: { file: string; error: string }[] = []; for (const filePath of allXmlFiles) { try { // Read XML content const xmlContent = await fs.readFile(filePath, 'utf-8'); // Track performance of XML validation const { result: isValid } = await PerformanceTracker.track( 'xml-syntax-validation', async () => { try { // Use DOMParser to validate XML syntax const parser = new DOMParser(); const doc = parser.parseFromString(xmlContent, 'application/xml'); // Check for parsing errors const parseError = doc.getElementsByTagName('parsererror'); if (parseError.length > 0) { throw new Error(`XML Parse Error: ${parseError[0].textContent}`); } // Additional basic validation if (!doc.documentElement) { throw new Error('No document element found'); } return true; } catch (error) { throw error; } }, { file: path.basename(filePath), size: xmlContent.length } ); if (isValid) { validCount++; } else { invalidCount++; } } catch (error) { invalidCount++; errors.push({ file: path.basename(filePath), error: error.message }); } } // Report results console.log(`\nXML Syntax Validation Results:`); console.log(`✓ Valid: ${validCount}/${allXmlFiles.length} (${(validCount/allXmlFiles.length*100).toFixed(1)}%)`); console.log(`✗ Invalid: ${invalidCount}/${allXmlFiles.length} (${(invalidCount/allXmlFiles.length*100).toFixed(1)}%)`); if (errors.length > 0) { console.log(`\nValidation Errors:`); errors.slice(0, 5).forEach(e => console.log(` - ${e.file}: ${e.error}`)); if (errors.length > 5) { console.log(` ... and ${errors.length - 5} more errors`); } } // Performance summary const perfSummary = await PerformanceTracker.getSummary('xml-syntax-validation'); 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 for XML syntax validation expect(validCount / allXmlFiles.length).toBeGreaterThan(0.95); }); tap.test('VAL-01: XML Well-formedness - should validate XML well-formedness', async () => { const testCases = [ { name: 'Valid XML', xml: ` TEST-001 `, shouldBeValid: true }, { name: 'Invalid XML - Unclosed tag', xml: ` TEST-001`, shouldBeValid: false }, { name: 'Invalid XML - Mismatched tags', xml: ` TEST-001 `, shouldBeValid: false }, { name: 'Invalid XML - Invalid characters', xml: ` TEST-001 & invalid `, shouldBeValid: false } ]; for (const testCase of testCases) { try { const { result: isValid } = await PerformanceTracker.track( 'xml-wellformedness-check', async () => { try { const parser = new DOMParser(); const doc = parser.parseFromString(testCase.xml, 'application/xml'); const parseError = doc.getElementsByTagName('parsererror'); return parseError.length === 0 && doc.documentElement !== null; } catch (error) { return false; } } ); console.log(`${testCase.name}: ${isValid ? 'Valid' : 'Invalid'}`); expect(isValid).toEqual(testCase.shouldBeValid); } catch (error) { console.log(`${testCase.name}: Error - ${error.message}`); expect(testCase.shouldBeValid).toEqual(false); } } }); tap.test('VAL-01: XML Encoding Validation - should handle different encodings', async () => { const encodingTests = [ { name: 'UTF-8 encoding', xml: ` Tëst-001`, encoding: 'utf-8' }, { name: 'ISO-8859-1 encoding', xml: ` Test-001`, encoding: 'iso-8859-1' } ]; for (const test of encodingTests) { const { result: isValid } = await PerformanceTracker.track( 'xml-encoding-validation', async () => { try { const parser = new DOMParser(); const doc = parser.parseFromString(test.xml, 'application/xml'); const parseError = doc.getElementsByTagName('parsererror'); return parseError.length === 0; } catch (error) { return false; } } ); console.log(`${test.name}: ${isValid ? 'Valid' : 'Invalid'}`); expect(isValid).toEqual(true); } }); tap.start();