Quelltext des aktuellen Standes
<?php
declare(strict_types=1);
use OpenNIT\Content\VersionManager;
/**
* Deckt ab, dass Seiten schreibende Aufrufer zur Umsetzung passen.
*
* Eine falsche Argumentzahl oder eine Spalte, die es nicht gibt, fällt erst zur
* Laufzeit auf – und in Pfaden mit eigenem catch bleibt davon nur eine
* allgemeine Meldung übrig. Beides wird deshalb hier festgehalten.
*/
return static function (): void {
/** @return list<string> Alle PHP-Dateien unterhalb von src/ */
$quellen = static function (): array {
$dateien = [];
$lauf = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(dirname(__DIR__) . '/src', FilesystemIterator::SKIP_DOTS)
);
foreach ($lauf as $datei) {
if ($datei->isFile() && $datei->getExtension() === 'php') {
$dateien[] = $datei->getPathname();
}
}
sort($dateien);
return $dateien;
};
// ----------------------------------------------------------------
// Argumentzahl des VersionManagers
// ----------------------------------------------------------------
test('Der VersionManager verlangt Datenbank und Audit-Log', function () {
$ctor = (new ReflectionClass(VersionManager::class))->getConstructor();
assertTrue($ctor !== null, 'Kein Konstruktor gefunden');
assertSame(2, $ctor->getNumberOfRequiredParameters());
});
test('Jeder Aufrufer übergibt beide Abhängigkeiten', function () use ($quellen) {
$ctor = (new ReflectionClass(VersionManager::class))->getConstructor();
$noetig = $ctor->getNumberOfRequiredParameters();
$gefunden = 0;
foreach ($quellen() as $datei) {
$inhalt = (string)file_get_contents($datei);
if (!preg_match_all('/new VersionManager\(([^)]*)\)/', $inhalt, $treffer)) {
continue;
}
foreach ($treffer[1] as $argumente) {
$gefunden++;
$anzahl = trim($argumente) === '' ? 0 : count(explode(',', $argumente));
assertSame(
$noetig,
$anzahl,
'Zu wenige Argumente in ' . basename($datei) . ': new VersionManager(' . $argumente . ')'
);
}
}
assertTrue($gefunden > 0, 'Keine Instanziierung gefunden – die Prüfung liefe ins Leere');
});
// ----------------------------------------------------------------
// Geschriebene Spalten der Tabelle pages
// ----------------------------------------------------------------
test('Auf pages werden nur vorhandene Spalten geschrieben', function () use ($quellen) {
// Spaltenbestand aus den Migrationen ableiten: Definition plus spätere
// ADD COLUMN. Nur so fällt eine erfundene Spalte ohne Datenbank auf.
$spalten = [];
foreach (glob(dirname(__DIR__) . '/database/migrations/*.sql') ?: [] as $sql) {
$inhalt = (string)file_get_contents($sql);
if (preg_match('/CREATE TABLE IF NOT EXISTS `pages` \((.*?)\n\) ENGINE/s', $inhalt, $m)) {
preg_match_all('/^\s*`([a-z_]+)`\s+[A-Z]/mi', $m[1], $sm);
$spalten = array_merge($spalten, $sm[1]);
}
if (preg_match_all('/ALTER TABLE `?pages`?\s+(.*?);/s', $inhalt, $am)) {
foreach ($am[1] as $block) {
preg_match_all('/ADD COLUMN `?([a-z_]+)`?/i', $block, $cm);
$spalten = array_merge($spalten, $cm[1]);
}
}
}
$spalten = array_unique($spalten);
assertTrue(in_array('current_version_id', $spalten, true), 'Spaltenbestand wurde nicht erkannt');
foreach ($quellen() as $datei) {
$inhalt = (string)file_get_contents($datei);
if (!preg_match_all("/update\(\s*'pages'\s*,\s*\[(.*?)\]/s", $inhalt, $treffer)) {
continue;
}
foreach ($treffer[1] as $block) {
preg_match_all("/'([a-z_]+)'\s*=>/", $block, $km);
foreach ($km[1] as $spalte) {
assertTrue(
in_array($spalte, $spalten, true),
'Unbekannte Spalte "' . $spalte . '" in ' . basename($datei)
);
}
}
}
});
// ----------------------------------------------------------------
// Seite und erste Version entstehen gemeinsam
// ----------------------------------------------------------------
test('Die vom KI-Chat angelegte Seite entsteht in einer Transaktion', function () {
// Bricht die Versionserstellung ab, darf keine Seite ohne Inhalt zurückbleiben.
$src = (string)file_get_contents(dirname(__DIR__) . '/src/Controllers/AIChatController.php');
$start = strpos($src, 'private function createPageFromChat');
assertTrue($start !== false, 'Die Aktion wurde nicht gefunden');
$block = substr($src, $start, 3000);
assertTrue(str_contains($block, 'beginTransaction()'), 'Keine Transaktion');
assertTrue(str_contains($block, 'commit()'), 'Kein Abschluss');
assertTrue(str_contains($block, 'rollback()'), 'Kein Rückbau bei Abbruch');
assertTrue(
strpos($block, 'beginTransaction()') < strpos($block, "insert('pages'"),
'Der Insert liegt außerhalb der Transaktion'
);
});
};