einvoice/test/suite/einvoice_edge-cases/test.edge-02.gigabyte-files.ts

314 lines
11 KiB
TypeScript

import { tap, expect } from '@git.zone/tstest/tapbundle';
import { EInvoice } from '../../../ts/index.js';
import { PerformanceTracker } from '../../helpers/performance.tracker.js';
import { ValidationLevel } from '../../../ts/interfaces/common.js';
tap.test('EDGE-02: Gigabyte-Size Invoices - should handle extremely large invoice files', async () => {
console.log('Testing large invoice handling...');
// Test 1: Invoice with many line items
console.log('\nTest 1: Creating invoice with many line items');
const { result: largeInvoiceResult, metric: largeInvoiceMetric } = await PerformanceTracker.track(
'large-invoice-creation',
async () => {
const einvoice = new EInvoice();
// Set basic invoice data
einvoice.id = 'LARGE-INVOICE-001';
einvoice.issueDate = new Date('2024-01-01');
einvoice.currency = 'EUR';
// Set supplier
einvoice.from = {
type: 'company',
name: 'Test Supplier GmbH',
description: 'Large invoice test supplier',
address: {
streetName: 'Test Street',
houseNumber: '1',
postalCode: '12345',
city: 'Berlin',
country: 'DE'
},
status: 'active',
foundedDate: { year: 2020, month: 1, day: 1 },
registrationDetails: {
vatId: 'DE123456789',
registrationId: 'HRB 12345',
registrationName: 'Berlin Registry'
}
};
// Set customer
einvoice.to = {
type: 'company',
name: 'Test Customer AG',
description: 'Large invoice test customer',
address: {
streetName: 'Market Street',
houseNumber: '42',
postalCode: '54321',
city: 'Munich',
country: 'DE'
},
status: 'active',
foundedDate: { year: 2018, month: 6, day: 15 },
registrationDetails: {
vatId: 'DE987654321',
registrationId: 'HRB 54321',
registrationName: 'Munich Registry'
}
};
// Create many line items
const itemCount = 500; // Reasonable number for testing
einvoice.items = [];
for (let i = 0; i < itemCount; i++) {
einvoice.items.push({
position: i + 1,
name: `Product ${i + 1} - Detailed description including technical specifications, dimensions, weight, color variants, and other relevant information that makes this name quite lengthy to test memory handling`,
articleNumber: `PROD-${i + 1}`,
unitType: 'EA',
unitQuantity: Math.floor(Math.random() * 10) + 1,
unitNetPrice: 99.99,
vatPercentage: 19
});
}
// Test XML generation
const xmlGenStart = Date.now();
const xmlString = await einvoice.toXmlString('ubl');
const xmlGenTime = Date.now() - xmlGenStart;
// Test parsing back
const parseStart = Date.now();
const parsedInvoice = new EInvoice();
await parsedInvoice.fromXmlString(xmlString);
const parseTime = Date.now() - parseStart;
// Test validation
const validationStart = Date.now();
const validationResult = await parsedInvoice.validate(ValidationLevel.SYNTAX);
const validationTime = Date.now() - validationStart;
return {
itemCount,
xmlSize: Buffer.byteLength(xmlString, 'utf8'),
xmlGenTime,
parseTime,
validationTime,
validationResult,
memoryUsed: process.memoryUsage().heapUsed
};
}
);
console.log(` Created invoice with ${largeInvoiceResult.itemCount} items`);
console.log(` XML size: ${(largeInvoiceResult.xmlSize / 1024).toFixed(2)} KB`);
console.log(` XML generation time: ${largeInvoiceResult.xmlGenTime}ms`);
console.log(` Parse time: ${largeInvoiceResult.parseTime}ms`);
console.log(` Validation time: ${largeInvoiceResult.validationTime}ms`);
console.log(` Total processing time: ${largeInvoiceMetric.duration}ms`);
console.log(` Memory used: ${(largeInvoiceResult.memoryUsed / 1024 / 1024).toFixed(2)} MB`);
expect(largeInvoiceResult.itemCount).toEqual(500);
expect(largeInvoiceResult.xmlSize).toBeGreaterThan(50000); // At least 50KB
expect(largeInvoiceResult.validationResult.valid).toBeTrue();
// Test 2: Invoice with large text content
console.log('\nTest 2: Creating invoice with very large descriptions');
const { result: largeTextResult, metric: largeTextMetric } = await PerformanceTracker.track(
'large-text-content',
async () => {
const einvoice = new EInvoice();
// Set basic invoice data
einvoice.id = 'LARGE-TEXT-001';
einvoice.issueDate = new Date('2024-01-01');
einvoice.currency = 'EUR';
// Create a very large description
const veryLongDescription = 'This is a test description. '.repeat(1000); // ~30KB per item
einvoice.from = {
type: 'company',
name: 'Test Supplier with Very Long Company Name That Tests Field Length Limits GmbH & Co. KG',
description: veryLongDescription.substring(0, 5000), // Limit to reasonable size
address: {
streetName: 'Very Long Street Name That Goes On And On Testing Field Limits',
houseNumber: '999999',
postalCode: '99999',
city: 'City With Extremely Long Name Testing Municipality Name Length Limits',
country: 'DE'
},
status: 'active',
foundedDate: { year: 2020, month: 1, day: 1 },
registrationDetails: {
vatId: 'DE123456789',
registrationId: 'HRB 12345',
registrationName: 'Berlin Registry'
}
};
einvoice.to = {
type: 'company',
name: 'Customer Inc',
description: 'Normal customer',
address: {
streetName: 'Main St',
houseNumber: '1',
postalCode: '12345',
city: 'Berlin',
country: 'DE'
},
status: 'active',
foundedDate: { year: 2019, month: 3, day: 10 },
registrationDetails: {
vatId: 'DE987654321',
registrationId: 'HRB 98765',
registrationName: 'Berlin Registry'
}
};
// Add items with large descriptions
einvoice.items = [];
for (let i = 0; i < 10; i++) {
einvoice.items.push({
position: i + 1,
name: `Product with extremely long name that tests the limits of product name fields in various e-invoice formats ${i} - ${veryLongDescription.substring(0, 1000)}`,
articleNumber: `LONG-${i + 1}`,
unitType: 'EA',
unitQuantity: 1,
unitNetPrice: 100,
vatPercentage: 19
});
}
// Test XML generation
const xmlString = await einvoice.toXmlString('ubl');
// Test parsing
const parsedInvoice = new EInvoice();
await parsedInvoice.fromXmlString(xmlString);
return {
xmlSize: Buffer.byteLength(xmlString, 'utf8'),
itemCount: parsedInvoice.items?.length || 0,
fromNameLength: parsedInvoice.from?.name?.length || 0,
itemNameLength: parsedInvoice.items?.[0]?.name?.length || 0
};
}
);
console.log(` XML size with large text: ${(largeTextResult.xmlSize / 1024).toFixed(2)} KB`);
console.log(` Processing time: ${largeTextMetric.duration}ms`);
console.log(` Preserved ${largeTextResult.itemCount} items`);
console.log(` Company name length: ${largeTextResult.fromNameLength} chars`);
console.log(` Item name length: ${largeTextResult.itemNameLength} chars`);
expect(largeTextResult.xmlSize).toBeGreaterThan(30000); // At least 30KB
expect(largeTextResult.itemCount).toEqual(10);
// Test 3: Memory efficiency test
console.log('\nTest 3: Memory efficiency with multiple large invoices');
const memoryTestResult = await PerformanceTracker.track(
'memory-efficiency',
async () => {
const startMemory = process.memoryUsage().heapUsed;
const invoices = [];
// Create multiple invoices
for (let i = 0; i < 10; i++) {
const invoice = new EInvoice();
invoice.id = `MEMORY-TEST-${i}`;
invoice.issueDate = new Date();
invoice.currency = 'EUR';
invoice.from = {
type: 'company',
name: `Supplier ${i}`,
description: 'Test supplier',
address: {
streetName: 'Test St',
houseNumber: '1',
postalCode: '12345',
city: 'Berlin',
country: 'DE'
},
status: 'active',
foundedDate: { year: 2020, month: 1, day: 1 },
registrationDetails: {
vatId: `DE12345678${i}`,
registrationId: `HRB 1234${i}`,
registrationName: 'Berlin Registry'
}
};
invoice.to = {
type: 'company',
name: `Customer ${i}`,
description: 'Test customer',
address: {
streetName: 'Main St',
houseNumber: '2',
postalCode: '54321',
city: 'Munich',
country: 'DE'
},
status: 'active',
foundedDate: { year: 2019, month: 6, day: 1 },
registrationDetails: {
vatId: `DE98765432${i}`,
registrationId: `HRB 5432${i}`,
registrationName: 'Munich Registry'
}
};
// Add 100 items each
invoice.items = [];
for (let j = 0; j < 100; j++) {
invoice.items.push({
position: j + 1,
name: `Product ${j} - Description for invoice ${i} item ${j}`,
articleNumber: `MEM-${i}-${j}`,
unitType: 'EA',
unitQuantity: 2,
unitNetPrice: 50,
vatPercentage: 19
});
}
invoices.push(invoice);
}
// Convert all to XML
const xmlStrings = await Promise.all(
invoices.map(inv => inv.toXmlString('ubl'))
);
const endMemory = process.memoryUsage().heapUsed;
const totalSize = xmlStrings.reduce((sum, xml) => sum + Buffer.byteLength(xml, 'utf8'), 0);
return {
invoiceCount: invoices.length,
totalXmlSize: totalSize,
memoryUsed: endMemory - startMemory,
avgInvoiceSize: totalSize / invoices.length
};
}
);
console.log(` Created ${memoryTestResult.result.invoiceCount} invoices`);
console.log(` Total XML size: ${(memoryTestResult.result.totalXmlSize / 1024 / 1024).toFixed(2)} MB`);
console.log(` Memory used: ${(memoryTestResult.result.memoryUsed / 1024 / 1024).toFixed(2)} MB`);
console.log(` Average invoice size: ${(memoryTestResult.result.avgInvoiceSize / 1024).toFixed(2)} KB`);
console.log(` Processing time: ${memoryTestResult.metric.duration}ms`);
expect(memoryTestResult.result.invoiceCount).toEqual(10);
expect(memoryTestResult.result.totalXmlSize).toBeGreaterThan(500000); // At least 500KB total
console.log('\n✓ All large invoice tests completed successfully');
});
tap.start();