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:
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();
|
Reference in New Issue
Block a user