← Code-Übersicht

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";
    }
}