Steuerkram/tests/99_ViewKlassenImportTest.php

96 lines
3.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
/**
* Test 99: Klassen-Importe in den Views (Fix für /suppliers, HTTP 500)
*
* Views werden per include eingebunden und laufen dadurch im globalen
* Namespace – das `use Steuerkram\View;` des einbindenden Controllers gilt
* dort nicht. Fehlt der Import in der View selbst, wird `View::formatDate()`
* zu `\View::formatDate()` und die Seite stirbt mit "Class View not found".
*
* Der Fehler bleibt so lange unsichtbar, wie die betroffene Zeile nicht
* ausgeführt wird (in suppliers/list.php stand sie in einer foreach-Schleife,
* schlug also erst mit dem ersten Lieferanten zu). Dieser Test prüft alle
* Views statisch, damit ein fehlender Import nicht erst im Betrieb auffällt.
*/
class ViewKlassenImportTest extends TestCase
{
protected string $testName = 'Test 99: Klassen-Importe in den Views';
public function run(): void
{
$viewDir = realpath(__DIR__ . '/../src/Views');
$this->assert($viewDir !== false, 'src/Views/ existiert');
$dateien = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($viewDir));
$geprueft = 0;
$fehler = [];
foreach ($dateien as $datei) {
if (!$datei->isFile() || $datei->getExtension() !== 'php') {
continue;
}
$inhalt = file_get_contents($datei->getPathname());
$relativ = str_replace($viewDir . '/', '', $datei->getPathname());
$geprueft++;
foreach ($this->unaufgeloesteKlassen($inhalt) as $klasse) {
$fehler[] = "$relativ verwendet $klasse:: ohne Import";
}
}
$this->assertGreaterThan(20, $geprueft, 'Es wurden Views eingelesen');
$this->assert(
$fehler === [],
'Jede View importiert die Klassen, die sie statisch aufruft'
. ($fehler === [] ? '' : ': ' . implode('; ', $fehler))
);
}
/**
* Liefert die in $inhalt statisch aufgerufenen Klassennamen, die weder
* global existieren noch per use-Statement importiert sind.
*
* @return string[]
*/
private function unaufgeloesteKlassen(string $inhalt): array
{
preg_match_all(
'/\buse\s+([A-Za-z0-9_\\\\]+)(?:\s+as\s+([A-Za-z0-9_]+))?\s*;/i',
$inhalt,
$useTreffer,
PREG_SET_ORDER
);
$importiert = [];
foreach ($useTreffer as $treffer) {
$teile = explode('\\', $treffer[1]);
$name = $treffer[2] ?? end($teile);
$importiert[$name] = true;
}
// Aufrufe wie View::formatDate(), aber nicht \Steuerkram\View::,
// $obj::, self::/static::/parent::
preg_match_all('/(?<![\\\\$\w>])([A-Z][A-Za-z0-9_]*)\s*::/', $inhalt, $aufrufe);
$offen = [];
foreach (array_unique($aufrufe[1]) as $klasse) {
if (isset($importiert[$klasse])) {
continue;
}
// Global existierende Klassen (DateTime, PDO, …) sind unkritisch.
if (class_exists($klasse, false) || interface_exists($klasse, false) || enum_exists($klasse, false)) {
continue;
}
if (class_exists('\\' . $klasse) || interface_exists('\\' . $klasse)) {
continue;
}
$offen[] = $klasse;
}
return $offen;
}
}