fix(tests): Fixed ENC-01, ENC-02, and ENC-03 encoding tests
- Fixed UTF-8 encoding test (ENC-01) to accept multiple encoding declarations - Fixed UTF-16 encoding test (ENC-02) by rewriting with correct API usage - Fixed ISO-8859-1 encoding test (ENC-03) with proper address fields and methods - All three encoding tests now pass successfully - Updated edge-cases tests (EDGE-02 through EDGE-07) with new test structure
This commit is contained in:
parent
a5b2d435d4
commit
784a50bc7f
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,311 +1,325 @@
|
||||
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
||||
import { EInvoice } from '../../../ts/index.js';
|
||||
import { PerformanceTracker } from '../performance.tracker.js';
|
||||
|
||||
console.log('Starting ENC-02 UTF-16 encoding test...');
|
||||
|
||||
tap.test('ENC-02: UTF-16 Encoding - should handle UTF-16 encoded documents correctly', async () => {
|
||||
console.log('Test function started');
|
||||
// ENC-02: Verify correct handling of UTF-16 encoded XML documents (both BE and LE)
|
||||
// This test ensures proper support for UTF-16 encoding variants
|
||||
|
||||
console.log('Testing UTF-16 encoding support...\n');
|
||||
|
||||
// Test 1: UTF-16 BE (Big Endian) encoding
|
||||
console.log('\nTest 1: UTF-16 BE (Big Endian) encoding');
|
||||
const { result: beResult, metric: beMetric } = await PerformanceTracker.track(
|
||||
'utf16-be',
|
||||
async () => {
|
||||
// Create UTF-16 BE content
|
||||
const xmlContent = `<?xml version="1.0" encoding="UTF-16BE"?>
|
||||
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
|
||||
<UBLVersionID>2.1</UBLVersionID>
|
||||
<ID>UTF16-BE-TEST</ID>
|
||||
<IssueDate>2025-01-25</IssueDate>
|
||||
<InvoiceTypeCode>380</InvoiceTypeCode>
|
||||
<DocumentCurrencyCode>EUR</DocumentCurrencyCode>
|
||||
<AccountingSupplierParty>
|
||||
<Party>
|
||||
<PartyName>
|
||||
<Name>UTF-16 BE Test Company</Name>
|
||||
</PartyName>
|
||||
</Party>
|
||||
</AccountingSupplierParty>
|
||||
<AccountingCustomerParty>
|
||||
<Party>
|
||||
<PartyName>
|
||||
<Name>Test Customer</Name>
|
||||
</PartyName>
|
||||
</Party>
|
||||
</AccountingCustomerParty>
|
||||
const testUtf16Be = async () => {
|
||||
// Create UTF-16 BE XML content with proper address fields
|
||||
const xmlContent = `<?xml version="1.0" encoding="UTF-16BE"?>
|
||||
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
|
||||
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
|
||||
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
|
||||
<cbc:ID>UTF16-BE-TEST</cbc:ID>
|
||||
<cbc:IssueDate>2025-01-25</cbc:IssueDate>
|
||||
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
|
||||
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
|
||||
<cac:AccountingSupplierParty>
|
||||
<cac:Party>
|
||||
<cac:PartyName>
|
||||
<cbc:Name>UTF-16 BE Test Company</cbc:Name>
|
||||
</cac:PartyName>
|
||||
<cac:PostalAddress>
|
||||
<cbc:StreetName>Test Street</cbc:StreetName>
|
||||
<cbc:CityName>Test City</cbc:CityName>
|
||||
<cbc:PostalZone>12345</cbc:PostalZone>
|
||||
<cac:Country>
|
||||
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
|
||||
</cac:Country>
|
||||
</cac:PostalAddress>
|
||||
</cac:Party>
|
||||
</cac:AccountingSupplierParty>
|
||||
<cac:AccountingCustomerParty>
|
||||
<cac:Party>
|
||||
<cac:PartyName>
|
||||
<cbc:Name>Test Customer</cbc:Name>
|
||||
</cac:PartyName>
|
||||
<cac:PostalAddress>
|
||||
<cbc:StreetName>Customer Street</cbc:StreetName>
|
||||
<cbc:CityName>Customer City</cbc:CityName>
|
||||
<cbc:PostalZone>54321</cbc:PostalZone>
|
||||
<cac:Country>
|
||||
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
|
||||
</cac:Country>
|
||||
</cac:PostalAddress>
|
||||
</cac:Party>
|
||||
</cac:AccountingCustomerParty>
|
||||
<cac:InvoiceLine>
|
||||
<cbc:ID>1</cbc:ID>
|
||||
<cbc:InvoicedQuantity unitCode="C62">1</cbc:InvoicedQuantity>
|
||||
<cbc:LineExtensionAmount currencyID="EUR">100.00</cbc:LineExtensionAmount>
|
||||
<cac:Item>
|
||||
<cbc:Name>Test Item</cbc:Name>
|
||||
</cac:Item>
|
||||
</cac:InvoiceLine>
|
||||
</Invoice>`;
|
||||
|
||||
// Convert to UTF-16 BE
|
||||
const utf16BeBuffer = Buffer.from(xmlContent, 'utf16le').swap16();
|
||||
|
||||
let success = false;
|
||||
let error = null;
|
||||
|
||||
try {
|
||||
// Try to load UTF-16 BE content
|
||||
const newInvoice = new EInvoice();
|
||||
await newInvoice.fromXmlString(utf16BeBuffer.toString('utf16le'));
|
||||
|
||||
// Check if invoice ID is preserved
|
||||
success = newInvoice.id === 'UTF16-BE-TEST' ||
|
||||
newInvoice.invoiceId === 'UTF16-BE-TEST' ||
|
||||
newInvoice.accountingDocId === 'UTF16-BE-TEST';
|
||||
} catch (e) {
|
||||
error = e;
|
||||
// UTF-16 might not be supported, which is acceptable
|
||||
console.log(' UTF-16 BE not supported:', e.message);
|
||||
}
|
||||
|
||||
return { success, error };
|
||||
|
||||
// Convert to UTF-16 BE
|
||||
const utf16BeBuffer = Buffer.from(xmlContent, 'utf16le').swap16();
|
||||
|
||||
try {
|
||||
// Try to load UTF-16 BE content
|
||||
const invoice = await EInvoice.fromXml(utf16BeBuffer.toString('utf16le'));
|
||||
return {
|
||||
success: true,
|
||||
parsed: invoice.id === 'UTF16-BE-TEST'
|
||||
};
|
||||
} catch (error) {
|
||||
// UTF-16 might not be supported, which is acceptable
|
||||
return {
|
||||
success: false,
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
console.log(` UTF-16 BE test completed in ${beMetric.duration}ms`);
|
||||
|
||||
};
|
||||
|
||||
const beResult = await testUtf16Be();
|
||||
console.log('Test 1 - UTF-16 BE (Big Endian):');
|
||||
console.log(` ${beResult.success ? 'Parsed successfully' : 'Not supported: ' + beResult.error}`);
|
||||
|
||||
// Test 2: UTF-16 LE (Little Endian) encoding
|
||||
console.log('\nTest 2: UTF-16 LE (Little Endian) encoding');
|
||||
const { result: leResult, metric: leMetric } = await PerformanceTracker.track(
|
||||
'utf16-le',
|
||||
async () => {
|
||||
// Create UTF-16 LE content
|
||||
const xmlContent = `<?xml version="1.0" encoding="UTF-16LE"?>
|
||||
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
|
||||
<UBLVersionID>2.1</UBLVersionID>
|
||||
<ID>UTF16-LE-TEST</ID>
|
||||
<IssueDate>2025-01-25</IssueDate>
|
||||
<InvoiceTypeCode>380</InvoiceTypeCode>
|
||||
<DocumentCurrencyCode>EUR</DocumentCurrencyCode>
|
||||
<AccountingSupplierParty>
|
||||
<Party>
|
||||
<PartyName>
|
||||
<Name>UTF-16 LE Test Company</Name>
|
||||
</PartyName>
|
||||
</Party>
|
||||
</AccountingSupplierParty>
|
||||
<AccountingCustomerParty>
|
||||
<Party>
|
||||
<PartyName>
|
||||
<Name>Test Customer</Name>
|
||||
</PartyName>
|
||||
</Party>
|
||||
</AccountingCustomerParty>
|
||||
const testUtf16Le = async () => {
|
||||
// Create UTF-16 LE XML content
|
||||
const xmlContent = `<?xml version="1.0" encoding="UTF-16LE"?>
|
||||
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
|
||||
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
|
||||
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
|
||||
<cbc:ID>UTF16-LE-TEST</cbc:ID>
|
||||
<cbc:IssueDate>2025-01-25</cbc:IssueDate>
|
||||
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
|
||||
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
|
||||
<cac:AccountingSupplierParty>
|
||||
<cac:Party>
|
||||
<cac:PartyName>
|
||||
<cbc:Name>UTF-16 LE Test Company</cbc:Name>
|
||||
</cac:PartyName>
|
||||
<cac:PostalAddress>
|
||||
<cbc:StreetName>Test Street</cbc:StreetName>
|
||||
<cbc:CityName>Test City</cbc:CityName>
|
||||
<cbc:PostalZone>12345</cbc:PostalZone>
|
||||
<cac:Country>
|
||||
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
|
||||
</cac:Country>
|
||||
</cac:PostalAddress>
|
||||
</cac:Party>
|
||||
</cac:AccountingSupplierParty>
|
||||
<cac:AccountingCustomerParty>
|
||||
<cac:Party>
|
||||
<cac:PartyName>
|
||||
<cbc:Name>Test Customer</cbc:Name>
|
||||
</cac:PartyName>
|
||||
<cac:PostalAddress>
|
||||
<cbc:StreetName>Customer Street</cbc:StreetName>
|
||||
<cbc:CityName>Customer City</cbc:CityName>
|
||||
<cbc:PostalZone>54321</cbc:PostalZone>
|
||||
<cac:Country>
|
||||
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
|
||||
</cac:Country>
|
||||
</cac:PostalAddress>
|
||||
</cac:Party>
|
||||
</cac:AccountingCustomerParty>
|
||||
<cac:InvoiceLine>
|
||||
<cbc:ID>1</cbc:ID>
|
||||
<cbc:InvoicedQuantity unitCode="C62">1</cbc:InvoicedQuantity>
|
||||
<cbc:LineExtensionAmount currencyID="EUR">100.00</cbc:LineExtensionAmount>
|
||||
<cac:Item>
|
||||
<cbc:Name>Test Item</cbc:Name>
|
||||
</cac:Item>
|
||||
</cac:InvoiceLine>
|
||||
</Invoice>`;
|
||||
|
||||
// Convert to UTF-16 LE
|
||||
const utf16LeBuffer = Buffer.from(xmlContent, 'utf16le');
|
||||
|
||||
let success = false;
|
||||
let error = null;
|
||||
|
||||
try {
|
||||
// Try to load UTF-16 LE content
|
||||
const newInvoice = new EInvoice();
|
||||
await newInvoice.fromXmlString(utf16LeBuffer.toString('utf16le'));
|
||||
|
||||
// Check if invoice ID is preserved
|
||||
success = newInvoice.id === 'UTF16-LE-TEST' ||
|
||||
newInvoice.invoiceId === 'UTF16-LE-TEST' ||
|
||||
newInvoice.accountingDocId === 'UTF16-LE-TEST';
|
||||
} catch (e) {
|
||||
error = e;
|
||||
// UTF-16 might not be supported, which is acceptable
|
||||
console.log(' UTF-16 LE not supported:', e.message);
|
||||
|
||||
// Convert to UTF-16 LE
|
||||
const utf16LeBuffer = Buffer.from(xmlContent, 'utf16le');
|
||||
|
||||
try {
|
||||
const invoice = await EInvoice.fromXml(utf16LeBuffer.toString('utf16le'));
|
||||
return {
|
||||
success: true,
|
||||
parsed: invoice.id === 'UTF16-LE-TEST'
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const leResult = await testUtf16Le();
|
||||
console.log('\nTest 2 - UTF-16 LE (Little Endian):');
|
||||
console.log(` ${leResult.success ? 'Parsed successfully' : 'Not supported: ' + leResult.error}`);
|
||||
|
||||
// Test 3: UTF-16 with BOM
|
||||
const testUtf16WithBom = async () => {
|
||||
const einvoice = new EInvoice();
|
||||
einvoice.id = 'UTF16-BOM-TEST';
|
||||
einvoice.date = Date.now();
|
||||
einvoice.currency = 'EUR';
|
||||
einvoice.subject = 'UTF-16 BOM test';
|
||||
|
||||
einvoice.from = {
|
||||
type: 'company',
|
||||
name: 'BOM Test Company',
|
||||
description: 'Test company',
|
||||
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'
|
||||
}
|
||||
|
||||
return { success, error };
|
||||
}
|
||||
);
|
||||
|
||||
console.log(` UTF-16 LE test completed in ${leMetric.duration}ms`);
|
||||
|
||||
// Test 3: UTF-16 auto-detection
|
||||
console.log('\nTest 3: UTF-16 auto-detection');
|
||||
const { result: autoResult, metric: autoMetric } = await PerformanceTracker.track(
|
||||
'utf16-auto',
|
||||
async () => {
|
||||
// Create invoice with UTF-16 characters
|
||||
const einvoice = new EInvoice();
|
||||
einvoice.id = 'UTF16-AUTO-TEST';
|
||||
einvoice.issueDate = new Date(2025, 0, 25);
|
||||
einvoice.invoiceId = 'UTF16-AUTO-TEST';
|
||||
einvoice.accountingDocId = 'UTF16-AUTO-TEST';
|
||||
einvoice.subject = 'UTF-16 auto-detection test';
|
||||
|
||||
einvoice.from = {
|
||||
type: 'company',
|
||||
name: 'Auto-detect Company',
|
||||
description: 'Test company for UTF-16 auto-detection',
|
||||
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: 'company',
|
||||
name: 'Customer Inc',
|
||||
description: 'Test customer',
|
||||
address: {
|
||||
streetName: 'Customer St',
|
||||
houseNumber: '2',
|
||||
postalCode: '54321',
|
||||
city: 'Customer City',
|
||||
country: 'US'
|
||||
},
|
||||
status: 'active',
|
||||
foundedDate: { year: 2020, month: 1, day: 1 },
|
||||
registrationDetails: {
|
||||
vatId: 'US987654321',
|
||||
registrationId: 'EIN 12-3456789',
|
||||
registrationName: 'IRS Registration'
|
||||
}
|
||||
};
|
||||
|
||||
einvoice.items = [{
|
||||
position: 1,
|
||||
name: 'Test Product',
|
||||
articleNumber: 'UTF16-001',
|
||||
unitType: 'EA',
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 100,
|
||||
vatPercentage: 19
|
||||
}];
|
||||
|
||||
// Export to XML
|
||||
const xmlString = await einvoice.toXmlString('ubl');
|
||||
|
||||
// Create UTF-16 with BOM
|
||||
const utf16Bom = Buffer.from([0xFE, 0xFF]); // UTF-16 BE BOM
|
||||
const utf16Content = Buffer.from(xmlString, 'utf16le').swap16();
|
||||
const withBom = Buffer.concat([utf16Bom, utf16Content]);
|
||||
|
||||
let success = false;
|
||||
let error = null;
|
||||
|
||||
try {
|
||||
// Try to load with BOM
|
||||
const newInvoice = new EInvoice();
|
||||
await newInvoice.fromXmlString(withBom.toString());
|
||||
|
||||
success = newInvoice.id === 'UTF16-AUTO-TEST' ||
|
||||
newInvoice.invoiceId === 'UTF16-AUTO-TEST' ||
|
||||
newInvoice.accountingDocId === 'UTF16-AUTO-TEST';
|
||||
} catch (e) {
|
||||
error = e;
|
||||
console.log(' UTF-16 auto-detection not supported:', e.message);
|
||||
};
|
||||
|
||||
einvoice.to = {
|
||||
type: 'company',
|
||||
name: 'Customer Inc',
|
||||
description: 'Test customer',
|
||||
address: {
|
||||
streetName: 'Customer St',
|
||||
houseNumber: '2',
|
||||
postalCode: '54321',
|
||||
city: 'Customer City',
|
||||
country: 'US'
|
||||
},
|
||||
status: 'active',
|
||||
foundedDate: { year: 2020, month: 1, day: 1 },
|
||||
registrationDetails: {
|
||||
vatId: 'US987654321',
|
||||
registrationId: 'EIN 12-3456789',
|
||||
registrationName: 'IRS Registration'
|
||||
}
|
||||
|
||||
return { success, error };
|
||||
}
|
||||
);
|
||||
|
||||
console.log(` UTF-16 auto-detection test completed in ${autoMetric.duration}ms`);
|
||||
|
||||
// Test 4: UTF-16 conversion fallback
|
||||
console.log('\nTest 4: UTF-16 conversion fallback to UTF-8');
|
||||
const { result: fallbackResult, metric: fallbackMetric } = await PerformanceTracker.track(
|
||||
'utf16-fallback',
|
||||
async () => {
|
||||
// Since UTF-16 might not be fully supported, test fallback to UTF-8
|
||||
const einvoice = new EInvoice();
|
||||
einvoice.id = 'UTF16-FALLBACK-TEST';
|
||||
einvoice.issueDate = new Date(2025, 0, 25);
|
||||
einvoice.invoiceId = 'UTF16-FALLBACK-TEST';
|
||||
einvoice.accountingDocId = 'UTF16-FALLBACK-TEST';
|
||||
einvoice.subject = 'UTF-16 fallback test: €£¥';
|
||||
|
||||
einvoice.from = {
|
||||
type: 'company',
|
||||
name: 'Fallback Company GmbH',
|
||||
description: 'Test company for UTF-16 fallback',
|
||||
address: {
|
||||
streetName: 'Hauptstraße',
|
||||
houseNumber: '42',
|
||||
postalCode: '80331',
|
||||
city: 'München',
|
||||
country: 'DE'
|
||||
},
|
||||
status: 'active',
|
||||
foundedDate: { year: 2020, month: 1, day: 1 },
|
||||
registrationDetails: {
|
||||
vatId: 'DE234567890',
|
||||
registrationId: 'HRB 23456',
|
||||
registrationName: 'Handelsregister München'
|
||||
}
|
||||
};
|
||||
|
||||
einvoice.items = [{
|
||||
position: 1,
|
||||
name: 'Test Product',
|
||||
unitType: 'C62',
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 100,
|
||||
vatPercentage: 19
|
||||
}];
|
||||
|
||||
// Export to XML
|
||||
const xmlString = await einvoice.toXmlString('ubl');
|
||||
|
||||
// Create UTF-16 with BOM
|
||||
const utf16Bom = Buffer.from([0xFE, 0xFF]); // UTF-16 BE BOM
|
||||
const utf16Content = Buffer.from(xmlString, 'utf16le').swap16();
|
||||
const withBom = Buffer.concat([utf16Bom, utf16Content]);
|
||||
|
||||
try {
|
||||
const invoice = await EInvoice.fromXml(withBom.toString());
|
||||
return {
|
||||
success: true,
|
||||
parsed: invoice.id === 'UTF16-BOM-TEST'
|
||||
};
|
||||
|
||||
einvoice.to = {
|
||||
type: 'company',
|
||||
name: 'Customer España S.L.',
|
||||
description: 'Spanish test customer',
|
||||
address: {
|
||||
streetName: 'Calle Mayor',
|
||||
houseNumber: '10',
|
||||
postalCode: '28001',
|
||||
city: 'Madrid',
|
||||
country: 'ES'
|
||||
},
|
||||
status: 'active',
|
||||
foundedDate: { year: 2020, month: 1, day: 1 },
|
||||
registrationDetails: {
|
||||
vatId: 'ES876543210',
|
||||
registrationId: 'B-87654321',
|
||||
registrationName: 'Registro Mercantil de Madrid'
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error.message
|
||||
};
|
||||
|
||||
einvoice.items = [{
|
||||
position: 1,
|
||||
name: 'Product with special chars: äöü',
|
||||
articleNumber: 'UTF16-FALLBACK-001',
|
||||
unitType: 'EA',
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 100,
|
||||
vatPercentage: 19
|
||||
}];
|
||||
|
||||
// Export as UTF-8 (our default)
|
||||
const utf8Xml = await einvoice.toXmlString('ubl');
|
||||
|
||||
// Verify UTF-8 works correctly
|
||||
const newInvoice = new EInvoice();
|
||||
await newInvoice.fromXmlString(utf8Xml);
|
||||
|
||||
const success = newInvoice.id === 'UTF16-FALLBACK-TEST' ||
|
||||
newInvoice.invoiceId === 'UTF16-FALLBACK-TEST' ||
|
||||
newInvoice.accountingDocId === 'UTF16-FALLBACK-TEST';
|
||||
|
||||
console.log(` UTF-8 fallback works: ${success}`);
|
||||
|
||||
return { success };
|
||||
}
|
||||
);
|
||||
|
||||
console.log(` UTF-16 fallback test completed in ${fallbackMetric.duration}ms`);
|
||||
|
||||
};
|
||||
|
||||
const bomResult = await testUtf16WithBom();
|
||||
console.log('\nTest 3 - UTF-16 with BOM:');
|
||||
console.log(` ${bomResult.success ? 'Parsed successfully' : 'Not supported: ' + bomResult.error}`);
|
||||
|
||||
// Test 4: UTF-8 fallback (should always work)
|
||||
const testUtf8Fallback = async () => {
|
||||
const einvoice = new EInvoice();
|
||||
einvoice.id = 'UTF8-FALLBACK-TEST';
|
||||
einvoice.date = Date.now();
|
||||
einvoice.currency = 'EUR';
|
||||
einvoice.subject = 'UTF-8 fallback test: €£¥';
|
||||
|
||||
einvoice.from = {
|
||||
type: 'company',
|
||||
name: 'Fallback Company GmbH',
|
||||
description: 'Test company for UTF-8',
|
||||
address: {
|
||||
streetName: 'Hauptstraße',
|
||||
houseNumber: '42',
|
||||
postalCode: '80331',
|
||||
city: 'München',
|
||||
country: 'DE'
|
||||
},
|
||||
status: 'active',
|
||||
foundedDate: { year: 2020, month: 1, day: 1 },
|
||||
registrationDetails: {
|
||||
vatId: 'DE234567890',
|
||||
registrationId: 'HRB 23456',
|
||||
registrationName: 'Handelsregister München'
|
||||
}
|
||||
};
|
||||
|
||||
einvoice.to = {
|
||||
type: 'company',
|
||||
name: 'Customer España S.L.',
|
||||
description: 'Spanish test customer',
|
||||
address: {
|
||||
streetName: 'Calle Mayor',
|
||||
houseNumber: '10',
|
||||
postalCode: '28001',
|
||||
city: 'Madrid',
|
||||
country: 'ES'
|
||||
},
|
||||
status: 'active',
|
||||
foundedDate: { year: 2020, month: 1, day: 1 },
|
||||
registrationDetails: {
|
||||
vatId: 'ES876543210',
|
||||
registrationId: 'B-87654321',
|
||||
registrationName: 'Registro Mercantil de Madrid'
|
||||
}
|
||||
};
|
||||
|
||||
einvoice.items = [{
|
||||
position: 1,
|
||||
name: 'Product with special chars: äöü',
|
||||
unitType: 'C62',
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 100,
|
||||
vatPercentage: 19
|
||||
}];
|
||||
|
||||
// Export as UTF-8 (our default)
|
||||
const utf8Xml = await einvoice.toXmlString('ubl');
|
||||
|
||||
// Verify UTF-8 works correctly
|
||||
const newInvoice = await EInvoice.fromXml(utf8Xml);
|
||||
|
||||
const success = newInvoice.id === 'UTF8-FALLBACK-TEST';
|
||||
const charsPreserved = newInvoice.from?.name === 'Fallback Company GmbH' &&
|
||||
newInvoice.from?.address?.city === 'München';
|
||||
|
||||
return { success, charsPreserved };
|
||||
};
|
||||
|
||||
const fallbackResult = await testUtf8Fallback();
|
||||
console.log('\nTest 4 - UTF-8 fallback:');
|
||||
console.log(` Invoice parsed: ${fallbackResult.success ? 'Yes' : 'No'}`);
|
||||
console.log(` Special chars preserved: ${fallbackResult.charsPreserved ? 'Yes' : 'No'}`);
|
||||
|
||||
// Summary
|
||||
console.log('\n=== UTF-16 Encoding Test Summary ===');
|
||||
console.log(`UTF-16 BE: ${beResult.success ? 'Supported' : 'Not supported (acceptable)'}`);
|
||||
console.log(`UTF-16 LE: ${leResult.success ? 'Supported' : 'Not supported (acceptable)'}`);
|
||||
console.log(`UTF-16 Auto-detection: ${autoResult.success ? 'Supported' : 'Not supported (acceptable)'}`);
|
||||
console.log(`UTF-16 with BOM: ${bomResult.success ? 'Supported' : 'Not supported (acceptable)'}`);
|
||||
console.log(`UTF-8 Fallback: ${fallbackResult.success ? 'Working' : 'Failed'}`);
|
||||
|
||||
// The test passes if UTF-8 fallback works, since UTF-16 support is optional
|
||||
expect(fallbackResult.success).toBeTrue();
|
||||
expect(fallbackResult.success).toEqual(true);
|
||||
expect(fallbackResult.charsPreserved).toEqual(true);
|
||||
|
||||
console.log('\n✓ UTF-16 encoding test completed');
|
||||
});
|
||||
|
||||
// Run the test
|
||||
tap.start();
|
@ -1,240 +1,328 @@
|
||||
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>
|
||||
console.log('Testing ISO-8859-1 (Latin-1) encoding support...\n');
|
||||
|
||||
// Test 1: Direct ISO-8859-1 encoding
|
||||
const testIso88591Direct = 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"
|
||||
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
|
||||
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
|
||||
<cbc:ID>ISO88591-TEST</cbc:ID>
|
||||
<cbc:IssueDate>2025-01-25</cbc:IssueDate>
|
||||
<cbc:Note>ISO-8859-1 Test: àáâãäåæçèéêëìíîïñòóôõöøùúûüý</cbc:Note>
|
||||
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
|
||||
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
|
||||
<cac:AccountingSupplierParty>
|
||||
<cac:Party>
|
||||
<cac:PartyName>
|
||||
<cbc:Name>Société Générale</cbc:Name>
|
||||
</cac:PartyName>
|
||||
<cac:PostalAddress>
|
||||
<cbc:StreetName>Rue de la Paix</cbc:StreetName>
|
||||
<cbc:CityName>Paris</cbc:CityName>
|
||||
<cbc:PostalZone>75001</cbc:PostalZone>
|
||||
<cac:Country>
|
||||
<cbc:IdentificationCode>FR</cbc:IdentificationCode>
|
||||
</cac:Country>
|
||||
</cac:PostalAddress>
|
||||
</cac:Party>
|
||||
</cac:AccountingSupplierParty>
|
||||
<cac:AccountingCustomerParty>
|
||||
<cac:Party>
|
||||
<cac:PartyName>
|
||||
<cbc:Name>Müller & Associés</cbc:Name>
|
||||
</cac:PartyName>
|
||||
<cac:PostalAddress>
|
||||
<cbc:StreetName>Königstraße</cbc:StreetName>
|
||||
<cbc:CityName>München</cbc:CityName>
|
||||
<cbc:PostalZone>80331</cbc:PostalZone>
|
||||
<cac:Country>
|
||||
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
|
||||
</cac:Country>
|
||||
</cac:PostalAddress>
|
||||
</cac:Party>
|
||||
</cac:AccountingCustomerParty>
|
||||
<cac:InvoiceLine>
|
||||
<cbc:ID>1</cbc:ID>
|
||||
<cbc:InvoicedQuantity unitCode="C62">1</cbc:InvoicedQuantity>
|
||||
<cbc:LineExtensionAmount currencyID="EUR">100.00</cbc:LineExtensionAmount>
|
||||
<cac:Item>
|
||||
<cbc:Name>Test Item</cbc:Name>
|
||||
</cac:Item>
|
||||
</cac:InvoiceLine>
|
||||
</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 };
|
||||
|
||||
// Convert to ISO-8859-1 buffer
|
||||
const iso88591Buffer = Buffer.from(xmlContent, 'latin1');
|
||||
|
||||
try {
|
||||
// Try to load ISO-8859-1 content
|
||||
const invoice = await EInvoice.fromXml(iso88591Buffer.toString('latin1'));
|
||||
return {
|
||||
success: true,
|
||||
parsed: invoice.id === 'ISO88591-TEST'
|
||||
};
|
||||
} catch (error) {
|
||||
// ISO-8859-1 might not be supported, which is acceptable
|
||||
return {
|
||||
success: false,
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
console.log(` ISO-8859-1 basic test completed in ${basicMetric.duration}ms`);
|
||||
|
||||
};
|
||||
|
||||
const directResult = await testIso88591Direct();
|
||||
console.log('Test 1 - Direct ISO-8859-1 encoding:');
|
||||
console.log(` ${directResult.success ? 'Parsed successfully' : 'Not supported: ' + directResult.error}`);
|
||||
|
||||
// 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'
|
||||
}
|
||||
const testUtf8Fallback = async () => {
|
||||
const einvoice = new EInvoice();
|
||||
einvoice.id = 'ISO88591-UTF8-TEST';
|
||||
einvoice.date = Date.now();
|
||||
einvoice.currency = 'EUR';
|
||||
einvoice.subject = 'ISO-8859-1 characters: àéïöü';
|
||||
einvoice.notes = ['French: crème brûlée', 'German: Müller & Söhne'];
|
||||
|
||||
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',
|
||||
unitType: 'C62',
|
||||
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 = await EInvoice.fromXml(utf8Xml);
|
||||
|
||||
const success = newInvoice.id === 'ISO88591-UTF8-TEST';
|
||||
const charactersPreserved =
|
||||
utf8Xml.includes('Société Française') &&
|
||||
utf8Xml.includes('Müller & Söhne') &&
|
||||
utf8Xml.includes('crème brûlée') &&
|
||||
utf8Xml.includes('München') &&
|
||||
utf8Xml.includes('Königstraße');
|
||||
|
||||
return { success, charactersPreserved };
|
||||
};
|
||||
|
||||
const fallbackResult = await testUtf8Fallback();
|
||||
console.log('\nTest 2 - UTF-8 fallback for Latin-1 characters:');
|
||||
console.log(` Invoice parsed: ${fallbackResult.success ? 'Yes' : 'No'}`);
|
||||
console.log(` Latin-1 chars preserved: ${fallbackResult.charactersPreserved ? 'Yes' : 'No'}`);
|
||||
|
||||
// Test 3: Extended Latin-1 character range
|
||||
const testExtendedRange = async () => {
|
||||
const einvoice = new EInvoice();
|
||||
|
||||
// Test high Latin-1 characters (0x80-0xFF)
|
||||
const highChars = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ';
|
||||
|
||||
einvoice.id = 'ISO88591-RANGE-TEST';
|
||||
einvoice.date = Date.now();
|
||||
einvoice.currency = 'EUR';
|
||||
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)}`,
|
||||
unitType: 'C62',
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 100,
|
||||
vatPercentage: 19
|
||||
}];
|
||||
|
||||
const xmlString = await einvoice.toXmlString('ubl');
|
||||
|
||||
// Check if characters are preserved (either directly or as entities)
|
||||
const preserved = highChars.split('').filter(char => {
|
||||
const charCode = char.charCodeAt(0);
|
||||
return xmlString.includes(char) ||
|
||||
xmlString.includes(`&#${charCode};`) ||
|
||||
xmlString.includes(`&#x${charCode.toString(16).toUpperCase()};`);
|
||||
}).length;
|
||||
const percentage = (preserved / highChars.length) * 100;
|
||||
|
||||
return {
|
||||
preserved,
|
||||
total: highChars.length,
|
||||
percentage,
|
||||
success: percentage > 50 // At least 50% should be preserved
|
||||
};
|
||||
};
|
||||
|
||||
const rangeResult = await testExtendedRange();
|
||||
console.log('\nTest 3 - Extended Latin-1 character range (0x80-0xFF):');
|
||||
console.log(` Characters preserved: ${rangeResult.preserved}/${rangeResult.total} (${rangeResult.percentage.toFixed(1)}%)`);
|
||||
|
||||
// Test 4: Mixed encoding scenario
|
||||
const testMixedEncoding = async () => {
|
||||
// Test with a document that mixes ASCII and Latin-1
|
||||
const mixedXml = `<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
|
||||
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
|
||||
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
|
||||
<cbc:ID>MIXED-TEST</cbc:ID>
|
||||
<cbc:IssueDate>2025-01-25</cbc:IssueDate>
|
||||
<cbc:Note>Mixed ASCII and Latin-1: café, naïve, résumé</cbc:Note>
|
||||
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
|
||||
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
|
||||
<cac:AccountingSupplierParty>
|
||||
<cac:Party>
|
||||
<cac:PartyName>
|
||||
<cbc:Name>ASCII Company</cbc:Name>
|
||||
</cac:PartyName>
|
||||
<cac:PostalAddress>
|
||||
<cbc:StreetName>Main Street</cbc:StreetName>
|
||||
<cbc:CityName>New York</cbc:CityName>
|
||||
<cbc:PostalZone>10001</cbc:PostalZone>
|
||||
<cac:Country>
|
||||
<cbc:IdentificationCode>US</cbc:IdentificationCode>
|
||||
</cac:Country>
|
||||
</cac:PostalAddress>
|
||||
</cac:Party>
|
||||
</cac:AccountingSupplierParty>
|
||||
<cac:AccountingCustomerParty>
|
||||
<cac:Party>
|
||||
<cac:PartyName>
|
||||
<cbc:Name>Café Société</cbc:Name>
|
||||
</cac:PartyName>
|
||||
<cac:PostalAddress>
|
||||
<cbc:StreetName>Avenue des Champs-Élysées</cbc:StreetName>
|
||||
<cbc:CityName>Paris</cbc:CityName>
|
||||
<cbc:PostalZone>75008</cbc:PostalZone>
|
||||
<cac:Country>
|
||||
<cbc:IdentificationCode>FR</cbc:IdentificationCode>
|
||||
</cac:Country>
|
||||
</cac:PostalAddress>
|
||||
</cac:Party>
|
||||
</cac:AccountingCustomerParty>
|
||||
<cac:InvoiceLine>
|
||||
<cbc:ID>1</cbc:ID>
|
||||
<cbc:InvoicedQuantity unitCode="C62">1</cbc:InvoicedQuantity>
|
||||
<cbc:LineExtensionAmount currencyID="EUR">100.00</cbc:LineExtensionAmount>
|
||||
<cac:Item>
|
||||
<cbc:Name>Café au lait</cbc:Name>
|
||||
</cac:Item>
|
||||
</cac:InvoiceLine>
|
||||
</Invoice>`;
|
||||
|
||||
try {
|
||||
const invoice = await EInvoice.fromXml(mixedXml);
|
||||
return {
|
||||
success: true,
|
||||
parsed: invoice.id === 'MIXED-TEST'
|
||||
};
|
||||
|
||||
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'
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error.message
|
||||
};
|
||||
|
||||
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 & 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`);
|
||||
|
||||
};
|
||||
|
||||
const mixedResult = await testMixedEncoding();
|
||||
console.log('\nTest 4 - Mixed ASCII/Latin-1 encoding:');
|
||||
console.log(` ${mixedResult.success ? 'Parsed successfully' : 'Not supported: ' + mixedResult.error}`);
|
||||
|
||||
// Summary
|
||||
console.log('\n=== ISO-8859-1 Encoding Test Summary ===');
|
||||
console.log(`ISO-8859-1 Direct: ${basicResult.success ? 'Supported' : 'Not supported (acceptable)'}`);
|
||||
console.log(`ISO-8859-1 Direct: ${directResult.success ? 'Supported' : 'Not supported (acceptable)'}`);
|
||||
console.log(`UTF-8 Fallback: ${fallbackResult.success ? 'Working' : 'Failed'}`);
|
||||
console.log(`Character Range: ${rangeResult.success ? 'Good coverage' : 'Limited coverage'}`);
|
||||
console.log(`Mixed Encoding: ${mixedResult.success ? 'Supported' : 'Not supported (acceptable)'}`);
|
||||
|
||||
// The test passes if UTF-8 fallback works, since ISO-8859-1 support is optional
|
||||
expect(fallbackResult.success).toBeTrue();
|
||||
expect(fallbackResult.success).toEqual(true);
|
||||
expect(fallbackResult.charactersPreserved).toEqual(true);
|
||||
|
||||
console.log('\n✓ ISO-8859-1 encoding test completed');
|
||||
});
|
||||
|
||||
// Run the test
|
||||
tap.start();
|
Loading…
x
Reference in New Issue
Block a user