einvoice/test/suite/einvoice_encoding/test.enc-03.iso88591-encoding.ts
2025-05-27 19:30:07 +00:00

240 lines
8.4 KiB
TypeScript

import { expect, tap } from '@git.zone/tstest/tapbundle';
import { EInvoice } from '../../../ts/index.js';
import { PerformanceTracker } from '../performance.tracker.js';
tap.test('ENC-03: ISO-8859-1 Encoding - should handle ISO-8859-1 (Latin-1) encoded documents', async () => {
// ENC-03: Verify correct handling of ISO-8859-1 encoded XML documents
// This test ensures support for legacy Western European character encoding
// Test 1: Basic ISO-8859-1 encoding
console.log('\nTest 1: Basic ISO-8859-1 encoding');
const { result: basicResult, metric: basicMetric } = await PerformanceTracker.track(
'iso88591-basic',
async () => {
// Create ISO-8859-1 content with Latin-1 specific characters
const xmlContent = `<?xml version="1.0" encoding="ISO-8859-1"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
<UBLVersionID>2.1</UBLVersionID>
<ID>ISO88591-TEST</ID>
<IssueDate>2025-01-25</IssueDate>
<Note>ISO-8859-1 Test: àáâãäåæçèéêëìíîïñòóôõöøùúûüý</Note>
<DocumentCurrencyCode>EUR</DocumentCurrencyCode>
<AccountingSupplierParty>
<Party>
<PartyName>
<Name>Société Générale</Name>
</PartyName>
</Party>
</AccountingSupplierParty>
<AccountingCustomerParty>
<Party>
<PartyName>
<Name>Müller & Associés</Name>
</PartyName>
</Party>
</AccountingCustomerParty>
</Invoice>`;
// Convert to ISO-8859-1 buffer
const iso88591Buffer = Buffer.from(xmlContent, 'latin1');
let success = false;
let error = null;
try {
// Try to load ISO-8859-1 content
const newInvoice = new EInvoice();
await newInvoice.fromXmlString(iso88591Buffer.toString('latin1'));
// Check if invoice ID is preserved
success = newInvoice.id === 'ISO88591-TEST' ||
newInvoice.invoiceId === 'ISO88591-TEST' ||
newInvoice.accountingDocId === 'ISO88591-TEST';
} catch (e) {
error = e;
// ISO-8859-1 might not be supported, which is acceptable
console.log(' ISO-8859-1 not supported:', e.message);
}
return { success, error };
}
);
console.log(` ISO-8859-1 basic test completed in ${basicMetric.duration}ms`);
// Test 2: UTF-8 fallback for Latin-1 characters
console.log('\nTest 2: UTF-8 fallback for Latin-1 characters');
const { result: fallbackResult, metric: fallbackMetric } = await PerformanceTracker.track(
'iso88591-fallback',
async () => {
// Create invoice with Latin-1 characters
const einvoice = new EInvoice();
einvoice.id = 'ISO88591-FALLBACK-TEST';
einvoice.issueDate = new Date(2025, 0, 25);
einvoice.invoiceId = 'ISO88591-FALLBACK-TEST';
einvoice.accountingDocId = 'ISO88591-FALLBACK-TEST';
einvoice.subject = 'ISO-8859-1 characters: àéïöü';
einvoice.from = {
type: 'company',
name: 'Société Française S.A.',
description: 'French company with accented characters',
address: {
streetName: 'Rue de la Paix',
houseNumber: '123',
postalCode: '75001',
city: 'Paris',
country: 'FR'
},
status: 'active',
foundedDate: { year: 2020, month: 1, day: 1 },
registrationDetails: {
vatId: 'FR12345678901',
registrationId: 'RCS Paris 123456789',
registrationName: 'Registre du Commerce et des Sociétés'
}
};
einvoice.to = {
type: 'company',
name: 'Müller & Söhne GmbH',
description: 'German company with umlauts',
address: {
streetName: 'Königstraße',
houseNumber: '45',
postalCode: '80331',
city: 'München',
country: 'DE'
},
status: 'active',
foundedDate: { year: 2020, month: 1, day: 1 },
registrationDetails: {
vatId: 'DE987654321',
registrationId: 'HRB 98765',
registrationName: 'Handelsregister München'
}
};
einvoice.items = [{
position: 1,
name: 'Spécialité française: crème brûlée',
articleNumber: 'ISO88591-001',
unitType: 'EA',
unitQuantity: 10,
unitNetPrice: 5.50,
vatPercentage: 19
}];
// Export as UTF-8 (our default)
const utf8Xml = await einvoice.toXmlString('ubl');
// Verify UTF-8 works correctly with Latin-1 characters
const newInvoice = new EInvoice();
await newInvoice.fromXmlString(utf8Xml);
const success = (newInvoice.id === 'ISO88591-FALLBACK-TEST' ||
newInvoice.invoiceId === 'ISO88591-FALLBACK-TEST' ||
newInvoice.accountingDocId === 'ISO88591-FALLBACK-TEST') &&
utf8Xml.includes('Société Française') &&
utf8Xml.includes('Müller &amp; Söhne') &&
utf8Xml.includes('crème brûlée');
console.log(` UTF-8 fallback works: ${success}`);
console.log(` Latin-1 chars preserved: ${utf8Xml.includes('àéïöü') || utf8Xml.includes('crème brûlée')}`);
return { success };
}
);
console.log(` ISO-8859-1 fallback test completed in ${fallbackMetric.duration}ms`);
// Test 3: Character range test
console.log('\nTest 3: ISO-8859-1 character range (0x80-0xFF)');
const { result: rangeResult, metric: rangeMetric } = await PerformanceTracker.track(
'iso88591-range',
async () => {
const einvoice = new EInvoice();
// Test high Latin-1 characters (0x80-0xFF)
const highChars = '¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ';
einvoice.id = 'ISO88591-RANGE-TEST';
einvoice.issueDate = new Date(2025, 0, 25);
einvoice.invoiceId = 'ISO88591-RANGE-TEST';
einvoice.accountingDocId = 'ISO88591-RANGE-TEST';
einvoice.subject = `Latin-1 range test: ${highChars}`;
einvoice.notes = [`Testing characters: ${highChars}`];
einvoice.from = {
type: 'company',
name: 'Test Company',
description: 'Testing ISO-8859-1 character range',
address: {
streetName: 'Test Street',
houseNumber: '1',
postalCode: '12345',
city: 'Test City',
country: 'DE'
},
status: 'active',
foundedDate: { year: 2020, month: 1, day: 1 },
registrationDetails: {
vatId: 'DE123456789',
registrationId: 'HRB 12345',
registrationName: 'Commercial Register'
}
};
einvoice.to = {
type: 'person',
name: 'Test',
surname: 'Customer',
salutation: 'Mr' as const,
sex: 'male' as const,
title: 'Doctor' as const,
description: 'Test customer',
address: {
streetName: 'Customer Street',
houseNumber: '2',
postalCode: '54321',
city: 'Customer City',
country: 'DE'
}
};
einvoice.items = [{
position: 1,
name: `Product with symbols: ${highChars.substring(0, 10)}`,
articleNumber: 'ISO88591-RANGE-001',
unitType: 'EA',
unitQuantity: 1,
unitNetPrice: 100,
vatPercentage: 19
}];
const xmlString = await einvoice.toXmlString('ubl');
// Check if some characters are preserved
const preserved = highChars.split('').filter(char => xmlString.includes(char)).length;
const percentage = (preserved / highChars.length) * 100;
console.log(` Characters preserved: ${preserved}/${highChars.length} (${percentage.toFixed(1)}%)`);
return { success: percentage > 50 }; // At least 50% should be preserved
}
);
console.log(` ISO-8859-1 range test completed in ${rangeMetric.duration}ms`);
// Summary
console.log('\n=== ISO-8859-1 Encoding Test Summary ===');
console.log(`ISO-8859-1 Direct: ${basicResult.success ? 'Supported' : 'Not supported (acceptable)'}`);
console.log(`UTF-8 Fallback: ${fallbackResult.success ? 'Working' : 'Failed'}`);
console.log(`Character Range: ${rangeResult.success ? 'Good coverage' : 'Limited coverage'}`);
// The test passes if UTF-8 fallback works, since ISO-8859-1 support is optional
expect(fallbackResult.success).toBeTrue();
});
// Run the test
tap.start();