import { expect, tap } from '@git.zone/tstest/tapbundle'; import { EInvoice } from '../../../ts/index.js'; tap.test('EDGE-05: Zero-Byte PDFs - should handle zero-byte and minimal PDF files', async () => { console.log('Testing zero-byte and minimal PDF handling...\n'); // Test 1: Truly zero-byte PDF const testZeroBytePdf = async () => { const zeroPDF = Buffer.alloc(0); try { const result = await EInvoice.fromPdf(zeroPDF); console.log('Test 1 - Zero-byte PDF:'); console.log(' Unexpectedly succeeded, result:', result); return { handled: false, error: null }; } catch (error) { console.log('Test 1 - Zero-byte PDF:'); console.log(' Properly failed with error:', error.message); return { handled: true, error: error.message }; } }; // Test 2: Minimal PDF structures const testMinimalPdfStructures = async () => { const minimalPDFs = [ { name: 'header-only', content: Buffer.from('%PDF-1.4') }, { name: 'header-and-eof', content: Buffer.from('%PDF-1.4\n%%EOF') }, { name: 'empty-catalog', content: Buffer.from( '%PDF-1.4\n' + '1 0 obj\n<< /Type /Catalog >>\nendobj\n' + 'xref\n0 2\n' + '0000000000 65535 f\n' + '0000000009 00000 n\n' + 'trailer\n<< /Size 2 /Root 1 0 R >>\n' + 'startxref\n64\n%%EOF' ) }, { name: 'invalid-header', content: Buffer.from('NOT-A-PDF-HEADER') }, { name: 'truncated-pdf', content: Buffer.from('%PDF-1.4\n1 0 obj\n<< /Type /Cat') } ]; const results = []; for (const pdf of minimalPDFs) { try { const result = await EInvoice.fromPdf(pdf.content); console.log(`\nTest 2.${pdf.name}:`); console.log(` Size: ${pdf.content.length} bytes`); console.log(` Extracted invoice: Yes`); console.log(` Result type: ${typeof result}`); results.push({ name: pdf.name, success: true, error: null }); } catch (error) { console.log(`\nTest 2.${pdf.name}:`); console.log(` Size: ${pdf.content.length} bytes`); console.log(` Error: ${error.message}`); results.push({ name: pdf.name, success: false, error: error.message }); } } return results; }; // Test 3: PDF with invalid content but correct headers const testInvalidContentPdf = async () => { const invalidContentPDFs = [ { name: 'binary-garbage', content: Buffer.concat([ Buffer.from('%PDF-1.4\n'), Buffer.from(Array(100).fill(0).map(() => Math.floor(Math.random() * 256))), Buffer.from('\n%%EOF') ]) }, { name: 'text-only', content: Buffer.from('%PDF-1.4\nThis is just plain text content\n%%EOF') }, { name: 'xml-content', content: Buffer.from('%PDF-1.4\ntest\n%%EOF') } ]; const results = []; for (const pdf of invalidContentPDFs) { try { const result = await EInvoice.fromPdf(pdf.content); console.log(`\nTest 3.${pdf.name}:`); console.log(` PDF parsed successfully: Yes`); console.log(` Invoice extracted: ${result ? 'Yes' : 'No'}`); results.push({ name: pdf.name, parsed: true, extracted: !!result }); } catch (error) { console.log(`\nTest 3.${pdf.name}:`); console.log(` Error: ${error.message}`); results.push({ name: pdf.name, parsed: false, extracted: false, error: error.message }); } } return results; }; // Test 4: Edge case PDF sizes const testEdgeCaseSizes = async () => { const edgeCasePDFs = [ { name: 'single-byte', content: Buffer.from('P') }, { name: 'minimal-header', content: Buffer.from('%PDF') }, { name: 'almost-valid-header', content: Buffer.from('%PDF-1') }, { name: 'very-large-empty', content: Buffer.concat([ Buffer.from('%PDF-1.4\n'), Buffer.alloc(10000, 0x20), // 10KB of spaces Buffer.from('\n%%EOF') ]) } ]; const results = []; for (const pdf of edgeCasePDFs) { try { await EInvoice.fromPdf(pdf.content); console.log(`\nTest 4.${pdf.name}:`); console.log(` Size: ${pdf.content.length} bytes`); console.log(` Processing successful: Yes`); results.push({ name: pdf.name, size: pdf.content.length, processed: true }); } catch (error) { console.log(`\nTest 4.${pdf.name}:`); console.log(` Size: ${pdf.content.length} bytes`); console.log(` Error: ${error.message}`); results.push({ name: pdf.name, size: pdf.content.length, processed: false, error: error.message }); } } return results; }; // Test 5: PDF with embedded XML but malformed structure const testMalformedEmbeddedXml = async () => { try { // Create a PDF-like structure with embedded XML-like content const malformedPdf = Buffer.from( '%PDF-1.4\n' + '1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n' + '2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n' + '3 0 obj\n<< /Type /Page /Parent 2 0 R >>\nendobj\n' + '4 0 obj\n<< /Type /EmbeddedFile /Filter /ASCIIHexDecode /Length 100 >>\n' + 'stream\n' + '3C696E766F6963653E3C2F696E766F6963653E\n' + // hex for 'endstream\nendobj\n' + 'xref\n0 5\n' + '0000000000 65535 f\n' + '0000000009 00000 n\n' + '0000000052 00000 n\n' + '0000000101 00000 n\n' + '0000000141 00000 n\n' + 'trailer\n<< /Size 5 /Root 1 0 R >>\n' + 'startxref\n241\n%%EOF' ); const result = await EInvoice.fromPdf(malformedPdf); console.log(`\nTest 5 - Malformed embedded XML:`); console.log(` PDF size: ${malformedPdf.length} bytes`); console.log(` Processing result: ${result ? 'Success' : 'No invoice found'}`); return { processed: true, result: !!result }; } catch (error) { console.log(`\nTest 5 - Malformed embedded XML:`); console.log(` Error: ${error.message}`); return { processed: false, error: error.message }; } }; // Run all tests const zeroByteResult = await testZeroBytePdf(); const minimalResults = await testMinimalPdfStructures(); const invalidContentResults = await testInvalidContentPdf(); const edgeCaseResults = await testEdgeCaseSizes(); const malformedResult = await testMalformedEmbeddedXml(); console.log(`\n=== Zero-Byte PDF Test Summary ===`); // Count results const minimalHandled = minimalResults.filter(r => r.error !== null).length; const invalidHandled = invalidContentResults.filter(r => r.error !== null).length; const edgeCaseHandled = edgeCaseResults.filter(r => r.error !== null).length; console.log(`Zero-byte PDF: ${zeroByteResult.handled ? 'Properly handled' : 'Unexpected behavior'}`); console.log(`Minimal PDFs: ${minimalHandled}/${minimalResults.length} properly handled`); console.log(`Invalid content PDFs: ${invalidHandled}/${invalidContentResults.length} properly handled`); console.log(`Edge case sizes: ${edgeCaseHandled}/${edgeCaseResults.length} properly handled`); console.log(`Malformed embedded XML: ${malformedResult.processed ? 'Processed' : 'Error handled'}`); // Test passes if the library properly handles edge cases without crashing // Zero-byte PDF should fail gracefully expect(zeroByteResult.handled).toBeTrue(); // At least some minimal PDFs should fail (they don't contain valid invoice data) const someMinimalFailed = minimalResults.some(r => !r.success); expect(someMinimalFailed).toBeTrue(); }); // Run the test tap.start();