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();