import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as plugins from '../plugins.js'; import { EInvoice } from '../../../ts/index.js'; import { CorpusLoader } from '../corpus.loader.js'; import { PerformanceTracker } from '../performance.tracker.js'; tap.test('ENC-06: Namespace Declarations - should handle XML namespace declarations correctly', async (t) => { // ENC-06: Verify proper encoding and handling of XML namespace declarations // This test ensures namespace prefixes, URIs, and default namespaces work correctly const performanceTracker = new PerformanceTracker('ENC-06: Namespace Declarations'); const corpusLoader = new CorpusLoader(); t.test('Default namespace declaration', async () => { const startTime = performance.now(); const xmlContent = ` 2.1 urn:cen.eu:en16931:2017 DEFAULT-NS-TEST 2025-01-25 380 EUR Test Supplier Test Customer 100.00 `; const einvoice = new EInvoice(); await einvoice.loadFromString(xmlContent); const xmlString = einvoice.getXmlString(); // Verify default namespace is preserved expect(xmlString).toContain('xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"'); expect(xmlString).toContain(''); expect(xmlString).not.toContain('xmlns:'); // No prefixed namespaces const elapsed = performance.now() - startTime; performanceTracker.addMeasurement('default-namespace', elapsed); }); t.test('Multiple namespace declarations', async () => { const startTime = performance.now(); const xmlContent = ` 2.1 urn:cen.eu:en16931:2017#conformant#urn:fdc:peppol.eu:2017:poacc:billing:international:peppol:3.0 urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 MULTI-NS-TEST 2025-01-25 380 EUR Namespace Test Supplier 100.00 `; const einvoice = new EInvoice(); await einvoice.loadFromString(xmlContent); const xmlString = einvoice.getXmlString(); // Verify all namespace declarations are preserved expect(xmlString).toContain('xmlns:ubl="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"'); expect(xmlString).toContain('xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"'); expect(xmlString).toContain('xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"'); expect(xmlString).toContain('xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"'); expect(xmlString).toContain('xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'); // Verify prefixed elements expect(xmlString).toContain(''); expect(xmlString).toContain(''); expect(xmlString).toContain(''); const elapsed = performance.now() - startTime; performanceTracker.addMeasurement('multiple-namespaces', elapsed); }); t.test('Nested namespace declarations', async () => { const startTime = performance.now(); const xmlContent = ` 2.1 NESTED-NS-TEST SIG-001 RSA-SHA256 DOC-001 2025-01-25T10:00:00Z `; const einvoice = new EInvoice(); await einvoice.loadFromString(xmlContent); const xmlString = einvoice.getXmlString(); // Verify nested namespaces are handled correctly expect(xmlString).toContain('xmlns:sig="urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-2"'); expect(xmlString).toContain('xmlns:sac="urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2"'); expect(xmlString).toContain('xmlns:xades="http://uri.etsi.org/01903/v1.3.2#"'); // Verify nested elements with namespaces expect(xmlString).toContain(' { const startTime = performance.now(); const xmlContent = ` NS-SPECIAL-CHARS 2025-01-25 Test GmbH & Co. KG Hauptstraße 42 München Net 30 days 2% if < 10 days Product "A" with special chars: €, £, ¥ 99.99 `; const einvoice = new EInvoice(); await einvoice.loadFromString(xmlContent); const xmlString = einvoice.getXmlString(); // Verify namespace prefixes with hyphens, underscores, dots expect(xmlString).toContain('xmlns:addr-info='); expect(xmlString).toContain('xmlns:pay_terms='); expect(xmlString).toContain('xmlns:item.details='); // Verify elements use correct prefixes expect(xmlString).toContain(' { const startTime = performance.now(); const xmlContent = ` URI-ENCODING-TEST Custom Extension Test with encoded URI Factura en español Value with fragment reference `; const einvoice = new EInvoice(); await einvoice.loadFromString(xmlContent); const xmlString = einvoice.getXmlString(); // Verify namespace URIs are properly encoded expect(xmlString).toContain('xmlns:ext="http://example.com/extensions?version=2.0&type=invoice"'); expect(xmlString).toContain('xmlns:intl="http://example.com/i18n/español/facturas"'); expect(xmlString).toContain('xmlns:spec="http://example.com/spec#fragment"'); // Verify elements with these namespaces expect(xmlString).toContain(''); expect(xmlString).toContain(''); expect(xmlString).toContain(''); const elapsed = performance.now() - startTime; performanceTracker.addMeasurement('uri-encoding', elapsed); }); t.test('Namespace inheritance and scoping', async () => { const startTime = performance.now(); const xmlContent = ` NS-SCOPE-TEST 2025-01-25 Item using inherited namespace 100.00 100.00 19.00 119.00 `; const einvoice = new EInvoice(); await einvoice.loadFromString(xmlContent); const xmlString = einvoice.getXmlString(); // Verify namespace scoping expect(xmlString).toContain('xmlns:root="urn:example:root:1.0"'); expect(xmlString).toContain('xmlns:shared="urn:example:shared:1.0"'); expect(xmlString).toContain('xmlns:local="urn:example:local:1.0"'); expect(xmlString).toContain('xmlns:calc="urn:example:calc:1.0"'); // Verify proper element prefixing expect(xmlString).toContain(''); expect(xmlString).toContain(''); expect(xmlString).toContain(''); const elapsed = performance.now() - startTime; performanceTracker.addMeasurement('namespace-scoping', elapsed); }); t.test('Corpus namespace analysis', async () => { const startTime = performance.now(); let processedCount = 0; const namespaceStats = { defaultNamespace: 0, prefixedNamespaces: 0, multipleNamespaces: 0, commonPrefixes: new Map() }; const files = await corpusLoader.getAllFiles(); const xmlFiles = files.filter(f => f.endsWith('.xml')); // Analyze namespace usage in corpus const sampleSize = Math.min(100, xmlFiles.length); const sample = xmlFiles.slice(0, sampleSize); for (const file of sample) { try { const content = await corpusLoader.readFile(file); let xmlString: string; if (Buffer.isBuffer(content)) { xmlString = content.toString('utf8'); } else { xmlString = content; } // Check for default namespace if (/xmlns\s*=\s*["'][^"']+["']/.test(xmlString)) { namespaceStats.defaultNamespace++; } // Check for prefixed namespaces const prefixMatches = xmlString.match(/xmlns:(\w+)\s*=\s*["'][^"']+["']/g); if (prefixMatches && prefixMatches.length > 0) { namespaceStats.prefixedNamespaces++; if (prefixMatches.length > 2) { namespaceStats.multipleNamespaces++; } // Count common prefixes prefixMatches.forEach(match => { const prefixMatch = match.match(/xmlns:(\w+)/); if (prefixMatch) { const prefix = prefixMatch[1]; namespaceStats.commonPrefixes.set( prefix, (namespaceStats.commonPrefixes.get(prefix) || 0) + 1 ); } }); } processedCount++; } catch (error) { console.log(`Namespace parsing issue in ${file}:`, error.message); } } console.log(`Namespace corpus analysis (${processedCount} files):`); console.log(`- Default namespace: ${namespaceStats.defaultNamespace}`); console.log(`- Prefixed namespaces: ${namespaceStats.prefixedNamespaces}`); console.log(`- Multiple namespaces: ${namespaceStats.multipleNamespaces}`); const topPrefixes = Array.from(namespaceStats.commonPrefixes.entries()) .sort((a, b) => b[1] - a[1]) .slice(0, 10); console.log('Top namespace prefixes:', topPrefixes); expect(processedCount).toBeGreaterThan(0); const elapsed = performance.now() - startTime; performanceTracker.addMeasurement('corpus-namespaces', elapsed); }); t.test('Namespace preservation during conversion', async () => { const startTime = performance.now(); const xmlContent = ` 2.1 NS-PRESERVE-TEST 2025-01-25 381 Müller GmbH `; const einvoice = new EInvoice(); await einvoice.loadFromString(xmlContent); // Process and get back const xmlString = einvoice.getXmlString(); // All original namespaces should be preserved expect(xmlString).toContain('xmlns:ubl='); expect(xmlString).toContain('xmlns:cac='); expect(xmlString).toContain('xmlns:cbc='); expect(xmlString).toContain('xmlns:xsi='); expect(xmlString).toContain('xsi:schemaLocation='); // Verify namespace prefixes are maintained expect(xmlString).toContain(''); expect(xmlString).toContain(''); expect(xmlString).toContain(''); const elapsed = performance.now() - startTime; performanceTracker.addMeasurement('namespace-preservation', elapsed); }); // Print performance summary performanceTracker.printSummary(); // Performance assertions const avgTime = performanceTracker.getAverageTime(); expect(avgTime).toBeLessThan(120); // Namespace operations should be reasonably fast }); tap.start();