$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 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); } }