PdftotextExtractorTest.php
Pfad: tests/Rechnung/PdftotextExtractorTest.php
Ext: php
Größe: 3777 Bytes
Geändert: 2026-07-16 17:59:44+02
<?php
declare(strict_types=1);
namespace Demo\Tests\Rechnung;
use Demo\Infrastructure\Rechnung\PdftotextExtractor;
use Demo\Infrastructure\Rechnung\TesseractInvoiceExtractor;
use PHPUnit\Framework\TestCase;
final class PdftotextExtractorTest extends TestCase
{
public function testExtractsCanonicalFieldsFromActualPdfFile(): void
{
$path = sys_get_temp_dir() . '/wetell-text-fixture-' . getmypid() . '.pdf';
file_put_contents($path, PdfTextFixture::create([
'WEtell GmbH',
'Gueterhallenstrasse 4',
'79106 Freiburg',
'Rechnungsnummer: RF183233049809',
'Rechnungsdatum: 04.07.2026',
'BETRAG EXKL. MWST. 26,0504',
'GESAMTRECHNUNGSBETRAG INKL. MWST. SUMME: 31,0000',
]));
$data = (new PdftotextExtractor('pdftotext'))->extract($path)->toArray();
self::assertSame('WEtell GmbH', $data['vendorName']);
self::assertSame('Gueterhallenstrasse 4|79106 Freiburg|DE', $data['vendorAddressSignature']);
self::assertSame('RF183233049809', $data['invoiceNumber']);
self::assertSame('2026-07-04', $data['invoiceDate']);
self::assertSame('26.0504', $data['netto']);
self::assertSame('4.9496', $data['steuer']);
self::assertSame('31.0000', $data['brutto']);
}
public function testExtractsCanonicalFieldsThroughRasterOcrFallback(): void
{
$path = sys_get_temp_dir() . '/wetell-ocr-fixture-' . getmypid() . '.pdf';
file_put_contents($path, PdfTextFixture::create([
'WEtell GmbH',
'Gueterhallenstrasse 4',
'79106 Freiburg',
'Rechnungsnummer: RF183233049809',
'Rechnungsdatum: 04.07.2026',
'BETRAG EXKL. MWST. 26,0504',
'GESAMTRECHNUNGSBETRAG INKL. MWST. SUMME: 31,0000',
]));
$data = (new TesseractInvoiceExtractor('/usr/bin/tesseract'))->extract($path)->toArray();
self::assertSame('RF183233049809', $data['invoiceNumber']);
self::assertSame('2026-07-04', $data['invoiceDate']);
self::assertSame('26.0504', $data['netto']);
self::assertSame('4.9496', $data['steuer']);
self::assertSame('31.0000', $data['brutto']);
}
}
final class PdfTextFixture
{
/** @param list<string> $lines */
public static function create(array $lines): string
{
$commands = ['BT', '/F1 11 Tf', '50 780 Td'];
foreach ($lines as $index => $line) {
if ($index > 0) { $commands[] = '0 -20 Td'; }
$commands[] = '(' . str_replace(['\\', '(', ')'], ['\\\\', '\\(', '\\)'], $line) . ') Tj';
}
$commands[] = 'ET';
$stream = implode("\n", $commands) . "\n";
$objects = [
'<< /Type /Catalog /Pages 2 0 R >>',
'<< /Type /Pages /Kids [3 0 R] /Count 1 >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 595 842] /Resources << /Font << /F1 4 0 R >> >> /Contents 5 0 R >>',
'<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>',
"<< /Length " . strlen($stream) . " >>\nstream\n" . $stream . 'endstream',
];
$pdf = "%PDF-1.4\n";
$offsets = [0];
foreach ($objects as $index => $object) {
$offsets[] = strlen($pdf);
$pdf .= ($index + 1) . " 0 obj\n" . $object . "\nendobj\n";
}
$xref = strlen($pdf);
$pdf .= "xref\n0 " . (count($objects) + 1) . "\n0000000000 65535 f \n";
foreach (array_slice($offsets, 1) as $offset) {
$pdf .= str_pad((string) $offset, 10, '0', STR_PAD_LEFT) . " 00000 n \n";
}
return $pdf . "trailer\n<< /Size " . (count($objects) + 1) . " /Root 1 0 R >>\nstartxref\n" . $xref . "\n%%EOF\n";
}
}