OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

ValueTooLongTest.php

4 KB
<?php

declare(strict_types=1);

use OpenNIT\Core\Database;

/**
 * Deckt die Erkennung zu langer Eingaben ab.
 *
 * Die Anwendung arbeitet mit STRICT_TRANS_TABLES: Ein Wert, der breiter ist als
 * seine Spalte, wird abgewiesen statt gekürzt. Das ist eine Frage der Eingabe
 * und keine Störung – erkannt wird sie deshalb eigens, damit die Oberfläche
 * etwas Brauchbares melden kann statt einer allgemeinen Fehlerseite.
 */
return static function (): void {

    /** Baut einen PDOException mit gesetztem errorInfo. */
    $pdoFehler = static function (string $sqlState, ?int $treiberCode, string $text): PDOException {
        $e = new PDOException($text, 0);
        // Der Code ist bei PDO der SQLSTATE, nicht der Treibercode.
        $reflex = new ReflectionClass(Exception::class);
        $p = $reflex->getProperty('code');
        $p->setAccessible(true);
        $p->setValue($e, $sqlState);
        $e->errorInfo = [$sqlState, $treiberCode, $text];
        return $e;
    };

    // ----------------------------------------------------------------
    // Erkennung
    // ----------------------------------------------------------------

    test('Der Zustand für zu lange Werte wird erkannt', function () use ($pdoFehler) {
        assertTrue(Database::isValueTooLongError(
            $pdoFehler('22001', 1406, "Data too long for column 'name' at row 1")
        ));
    });

    test('Auch der Treibercode allein genügt', function () use ($pdoFehler) {
        // Je nach Treiber steht der sprechende Code nur in errorInfo.
        assertTrue(Database::isValueTooLongError($pdoFehler('HY000', 1406, 'Data too long')));
        assertTrue(Database::isValueTooLongError($pdoFehler('HY000', 1265, 'Data truncated')));
    });

    test('Die Erkennung greift auch durch eine Umhüllung hindurch', function () use ($pdoFehler) {
        // execute() kapselt den PDO-Fehler, damit keine Schema-Details nach
        // außen dringen; die Einordnung muss trotzdem möglich bleiben.
        $gekapselt = new RuntimeException('Datenbankfehler', 0, $pdoFehler('22001', 1406, 'Data too long'));

        assertTrue(Database::isValueTooLongError($gekapselt));
    });

    // ----------------------------------------------------------------
    // Abgrenzung
    // ----------------------------------------------------------------

    test('Andere Datenbankfehler gelten nicht als zu lange Eingabe', function () use ($pdoFehler) {
        // Ein doppelter Schlüssel oder eine fehlende Spalte bleiben Störungen.
        assertFalse(Database::isValueTooLongError($pdoFehler('23000', 1062, 'Duplicate entry')));
        assertFalse(Database::isValueTooLongError($pdoFehler('42S22', 1054, "Unknown column 'x'")));
        assertFalse(Database::isValueTooLongError(new RuntimeException('irgendetwas')));
    });

    test('Die beiden Einordnungen schließen einander aus', function () use ($pdoFehler) {
        $zuLang   = $pdoFehler('22001', 1406, 'Data too long');
        $doppelt  = $pdoFehler('23000', 1062, 'Duplicate entry');

        assertTrue(Database::isValueTooLongError($zuLang));
        assertFalse(Database::isDuplicateKeyError($zuLang));
        assertTrue(Database::isDuplicateKeyError($doppelt));
        assertFalse(Database::isValueTooLongError($doppelt));
    });

    // ----------------------------------------------------------------
    // Auswertung im Front Controller
    // ----------------------------------------------------------------

    test('Der Front Controller wertet die Einordnung aus', function () {
        $index = (string)file_get_contents(dirname(__DIR__) . '/public/index.php');

        assertTrue(str_contains($index, 'isValueTooLongError'), 'Die Einordnung wird nicht genutzt');
        assertTrue(str_contains($index, '422'), 'Der eigene Status fehlt');
    });
};