# Unit-Tests der Votian-PHP-Altanwendung Die Suite prüft 14 Funktionen direkt aus dem aktuellen PHP-Quellstand. Sie enthält 144 fachliche Testfälle und fünf Tests des isolierten Funktionsladers. Anwendungsdateien und Composer-Konfiguration werden nicht verändert. ## Auf dem Server ausführen Die Suite liegt auf `172.16.0.158` unter `/data/0/votian-test/tests/unit`, außerhalb des Webroots. Aufruf auf diesem Server: ```sh cd /data/0/votian-test/tests/unit ./run-server.sh ``` Einzelnen Bereich ausführen: ```sh ./run-server.sh --filter PricingTest ./run-server.sh --filter RecurringOrderTest ``` Standardquelle ist `/data/0/votian-test/html`. Das Skript ermittelt die unveränderliche Image-ID des laufenden Containers `votian-test` und startet einen separaten Testcontainer mit genau diesem Image. Beim ersten geprüften Lauf war dessen PHP-Version **8.2.35**; das Host-PHP 8.2.30 wird nicht verwendet. Andere Quelle bzw. Laufzeit explizit auswählen: ```sh VOTIAN_SOURCE_ROOT=/pfad/zum/html VOTIAN_PHP_CONTAINER=votian-test ./run-server.sh ``` Ergebnisdateien in `reports/`: - `junit.xml`: maschinenlesbare Testergebnisse, mit Fehlermeldungen. - `source-manifest.json`: PHP-Version, Zeitzone, SHA-256 der fünf Quelldateien sowie Name, Ursprungszeile und SHA-256 jeder geladenen Funktion. - `runtime-image.txt`: genaue Docker-Image-ID des geprüften Laufzeitstands. Das Skript reicht den PHPUnit-Exitcode durch: **0 = erfolgreich, 1 = Testfehler**. Lade-, Konfigurations- und Laufzeitfehler werden ebenfalls als Fehler ausgegeben. JUnit-Bericht und Quellenmanifest werden bei jedem Lauf ersetzt. ## Installation aus dieser Repository-Kopie Benötigt werden Docker mit Zugriff auf das bereits vorhandene Votian-Image und PHPUnit 11.5.57. Der PHAR-Download ist nicht im Git-Repository enthalten: ```sh ./setup-phpunit.sh ``` Das Installationsskript lädt die feste Version von `phar.phpunit.de` und prüft SHA-256 `c704fdd37c6c6ab7adb386f31b4e186cd51156801fa9028b5ea8099a2cd7f106`. Auch der Teststarter prüft diese Prüfsumme. Ein Netzwerkzugriff ist nur für die Installation nötig. PHPUnit 11 passt zu PHP 8.2; siehe [offizielle Versionsmatrix](https://phpunit.de/supported-versions.html). Die Dateien dieses Ordners einschließlich `tools/phpunit.phar` können anschließend in das oben genannte Serververzeichnis kopiert werden. Der Teststarter erwartet Linux/Docker; die Tests selbst können bei passenden PHP-Erweiterungen auch direkt mit `VOTIAN_SOURCE_ROOT=/pfad/zum/html php tools/phpunit.phar -c phpunit.xml` laufen. Dieser direkte Aufruf bietet nicht die zusätzliche Container-Isolation. ## Abgedeckte Regeln | Datei | Regeln | | --- | --- | | `tests/CalendarTest.php` | Schaltjahre, Jahrhundertregeln, Monatslängen, Jahreswechsel, positive und negative Datumsabstände | | `tests/RecurringOrderTest.php` | Alle elf Wiederholungsrhythmen, Wochentagsmasken, konfigurierte Feiertage, Monatsende, Schaltjahr, Sommer-/Winterzeit | | `tests/PricingTest.php` | Kunden-/Standardtarife, Niederlassungsfallback, negative Preiskorrekturen, Rabattkorrekturen, Ein-Cent-Marker, Frachtvergütung, Rundung, Fahrzeug- und Kundenwahl | | `tests/InvoiceDiscountTest.php` | Bestehende Rabatt-/Zuschlagstexte, Servicepreisabgrenzung, Selbsterfasserrabatt, Reihenfolge und Beträge der BI-Positionen | | `tests/FormattingTest.php` | Zahl-/Datumsformatierung, Parameterfallback, Telefonnummern, exakte Listeneinträge | | `tests/ConditionTest.php` | Vergleichsoperatoren und bestehende PHP-Typumwandlung | | `tests/LegacyFunctionsTest.php` | Funktionsauswahl, Zeichenkettenklammern, keine Methoden-/Nested-Verwechslung, fehlende/mehrdeutige Funktionen, verbotene Includes | Die Rechnungstests charakterisieren den bestehenden Ausgabe- und BI-Vertrag; sie sind keine fachliche Freigabe sämtlicher Rabattregeln. Datenbankabfragen, Tarifdaten, Parameter und BI-Schreibziele werden durch strikt geprüfte Test-Doubles ersetzt. Nicht erwartete Zugriffe lassen einen Test fehlschlagen. Die Kalender- und Dauerauftragsfunktionen sind echte Serverfunktionen; die Feiertagsliste besteht aus synthetischen Daten und wird vor jedem Test zurückgesetzt. ## Isolation und Grenzen Die großen Legacy-Dateien enthalten Initialisierung mit Verbindungen und anderen Seiteneffekten. `support/LegacyFunctions.php` liest mit dem PHP-Tokenizer ausschließlich die benannten globalen Funktionsdefinitionen und führt deren unveränderte Bytes aus. Top-Level-Code, Includes, App-Bootstrap und Konfigurationsdateien werden nicht geladen. Fehlende bzw. doppelte Definitionen sowie Includes/Eval/Exit innerhalb ausgewählter Funktionen brechen den Lauf ab. Änderungen an den Serverfunktionen werden bei jedem Lauf direkt geprüft; es gibt keine eingefrorene Kopie der Geschäftslogik in den Tests. Der separate Container hat kein Netzwerk, nur lesbaren Quellcode, ein nur lesbares Root-Dateisystem, keine Linux-Capabilities und begrenzte Ressourcen. Schreibbar sind lediglich sein temporäres Verzeichnis und der Testberichtordner. Mailversand und Prozessstarts aus PHP sind zusätzlich deaktiviert. Der laufende Anwendungscontainer wird nicht verändert oder neu gestartet. Es werden keine Bestandsdaten gelesen oder geschrieben und keine Mails versandt. Nicht abgedeckt sind vollständige HTTP-/UI-Abläufe, reale SQL-Abfragen, Auftragsspeicherung, Rechnungserzeugung, Geräte-/Maildienste und alle übrigen Legacy-Funktionen. Es wird kein vollständiger Coverage-Prozentsatz behauptet. ## Befund vom 26. Oktober 2026 **149 Tests, 511 Assertions: 145 bestanden, vier fehlgeschlagen; keine Laufzeitfehler, keine übersprungenen Tests.** Die vier Fehlschläge betreffen denselben vorhandenen Fehler in `html/include/calendar.inc.php`, Funktion `addDaysComplete`, Zeile 213: Beim Rückwärtswechsel wird die Tageszahl des Ausgangsmonats statt des Zielmonats addiert. | Eingabe | Erwartet | Tatsächlich | | --- | --- | --- | | 01.03.2026 minus 1 Tag | 28.02.2026 | 31.02.2026 | | 01.03.2024 minus 1 Tag | 29.02.2024 | 31.02.2024 | | 01.05.2026 minus 1 Tag | 30.04.2026 | 31.04.2026 | | 01.04.2026 minus 1 Tag | 31.03.2026 | 30.03.2026 | Diese Regressionstests bleiben absichtlich aktiv und rot, bis der Anwendungsfehler behoben ist. Der Altcode wurde im Rahmen der Testerstellung nicht korrigiert.