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:
2025-05-28 12:52:08 +00:00
parent a5b2d435d4
commit 784a50bc7f
6 changed files with 2069 additions and 3267 deletions

View File

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