OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

SqlReservedAliasTest.php

3 KB
<?php

declare(strict_types=1);

/**
 * MySQL 8 und MariaDB reservieren unterschiedliche Wörter. Ein Alias wie
 * `AS system` läuft auf MariaDB durch und ist auf MySQL 8 ein Syntaxfehler –
 * die Abfrage scheitert dort bei jedem Aufruf, unabhängig von den Daten. Weil
 * die Suite ohne Datenbank läuft und der Migrations-Smoke-Test nur das Schema
 * anlegt, fiele so etwas sonst erst beim Betrieb auf einer MySQL-Instanz auf.
 *
 * Geprüft wird der Quelltext: Jeder Alias hinter `AS` muss entweder unverfänglich
 * oder in Backticks gesetzt sein.
 */
return static function (): void {

    $wurzel = dirname(__DIR__);

    /**
     * In MySQL 8.0 reservierte Wörter, die sich als Alias oder Spaltenname
     * anbieten (Fensterfunktionen und Verwandte, seit 8.0.3 reserviert).
     */
    $reserviert = [
        'system', 'rank', 'row', 'rows', 'groups', 'window', 'lead', 'lag', 'over',
        'recursive', 'empty', 'except', 'lateral', 'cube', 'grouping', 'of',
        'first_value', 'last_value', 'row_number', 'dense_rank', 'percent_rank',
        'cume_dist', 'ntile', 'nth_value', 'json_table',
    ];

    /** Alle PHP-Dateien unter src/. */
    $dateien = static function () use ($wurzel): array {
        $out = [];
        $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($wurzel . '/src'));
        foreach ($it as $d) {
            if ($d->isFile() && $d->getExtension() === 'php') {
                $out[] = $d->getPathname();
            }
        }
        sort($out);
        return $out;
    };

    test('Kein SQL-Alias trägt ein in MySQL 8 reserviertes Wort ohne Backticks', function () use ($dateien, $reserviert, $wurzel) {
        $muster = '/\bAS\s+(' . implode('|', $reserviert) . ')\b(?!\s*`)/i';
        $treffer = [];
        foreach ($dateien() as $datei) {
            $inhalt = (string)file_get_contents($datei);
            if (preg_match_all($muster, $inhalt, $m, PREG_OFFSET_CAPTURE)) {
                foreach ($m[1] as $einzel) {
                    $zeile = substr_count(substr($inhalt, 0, (int)$einzel[1]), "\n") + 1;
                    $treffer[] = str_replace($wurzel . '/', '', $datei) . ':' . $zeile . ' → AS ' . $einzel[0];
                }
            }
        }
        assertSame([], $treffer, 'Alias in Backticks setzen: ' . implode(' | ', $treffer));
    });

    test('Die Zählung des Software-Inventars nennt ihren Alias maskiert', function () use ($wurzel) {
        $quelle = (string)file_get_contents($wurzel . '/src/Software/SoftwareInventory.php');
        assertTrue(str_contains($quelle, 'AS `system`'), 'Der Alias der Systembestandteile ist nicht maskiert');
    });
};