Files

89 lines
3.1 KiB
PHP

<?php
declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Release;
use FilesystemIterator;
use LIT\MCP\Integrations\Divi\Release\DiviAdapter;
use LIT\MCP\Integrations\Divi\Release\DiviAdapters;
use LIT\MCP\Integrations\Divi\Release\DiviTouches;
use PHPUnit\Framework\TestCase;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use ReflectionClass;
/**
* Spec §3: only the adapters in DiviAdapters::CLASSES touch Divi, and every Divi name an adapter uses stands in its
* manifest (and nothing more).
*/
final class DiviBoundaryTest extends TestCase
{
public function testOnlyAdaptersTouchDivi(): void
{
$offenders = [];
foreach (self::sourceFiles() as $relative => $path) {
$touches = DiviTouches::inFile($path);
if ($touches === []) {
continue;
}
if (! in_array(self::classOf($relative), DiviAdapters::CLASSES, true)) {
$offenders[] = $relative . ': ' . implode(', ', array_unique(array_column($touches, 'name')));
}
}
self::assertSame([], $offenders, "Divi darf nur ein Adapter aus DiviAdapters::CLASSES berühren:\n"
. implode("\n", $offenders));
}
public function testAdaptersDeclareExactlyTheDiviNamesTheyUse(): void
{
foreach (DiviAdapters::CLASSES as $class) {
self::assertTrue(is_subclass_of($class, DiviAdapter::class), $class . ' implementiert DiviAdapter nicht');
$declared = $class::manifest()->names();
$used = array_values(array_unique(array_column(
DiviTouches::inFile((string) (new ReflectionClass($class))->getFileName()),
'name'
)));
self::assertSame([], array_values(array_diff($used, $declared)), $class . ': nicht im Manifest');
self::assertSame(
[],
array_values(array_diff(array_filter($declared, [DiviTouches::class, 'detects']), $used)),
$class . ': im Manifest, aber nicht benutzt'
);
}
}
public function testMirrorIdsAreUniqueAndFilesRelative(): void
{
$ids = [];
foreach (DiviAdapters::mirrors() as $mirror) {
self::assertNotContains($mirror->id, $ids, 'doppelte Mirror-ID ' . $mirror->id);
self::assertStringStartsNotWith('/', $mirror->file);
$ids[] = $mirror->id;
}
}
/** @return array<string, string> Path below src/ => absolute path. */
private static function sourceFiles(): array
{
$root = dirname(__DIR__, 5) . '/src/';
$files = [];
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS));
foreach ($iterator as $file) {
if ($file->getExtension() === 'php') {
$files[substr((string) $file->getPathname(), strlen($root))] = (string) $file->getPathname();
}
}
ksort($files);
return $files;
}
private static function classOf(string $relative): string
{
return 'LIT\\MCP\\' . str_replace(['/', '.php'], ['\\', ''], $relative);
}
}