$record['sha256'], $brand['logos']); $old = $brand['replace_from']; foreach ([[$old, 10], [$new, 0], [['docs/logo.svg' => $new['docs/logo.svg'], 'docs/logo-alt.svg' => $old['docs/logo-alt.svg']], 10], [['docs/logo.svg' => $old['docs/logo.svg'], 'docs/logo-alt.svg' => $new['docs/logo-alt.svg']], 10], [['docs/logo.svg' => 'unknown', 'docs/logo-alt.svg' => $new['docs/logo-alt.svg']], 1]] as [$actual, $state]) { if (prelandBrandState($actual, $brand) !== $state) throw new RuntimeException('Миграция бренда не восстанавливается после частичного put'); } try { prelandBrand($root, 'unregistered.example'); throw new LogicException('Неизвестная цель принята'); } catch (RuntimeException $expected) {} try { validateReleaseAssets($fixture); $mustFail = static function (callable $mutate) use ($fixture): void { $mutate(); try { validateReleaseAssets($fixture); } catch (RuntimeException $e) { return; } throw new RuntimeException('Повреждённый ресурс принят'); }; $mustFail(fn() => file_put_contents($fixture . '/docs/logo.svg', 'broken')); $copy('docs/logo.svg'); $mustFail(fn() => unlink($fixture . '/docs/public_offer.pdf')); $copy('docs/public_offer.pdf'); $mustFail(function () use ($fixture, $manifest): void { unset($manifest['files']['docs/logo-alt.svg']); file_put_contents($fixture . '/release/assets.json', json_encode($manifest)); }); $copy('release/assets.json'); $mustFail(function () use ($fixture, $manifest): void { $body = 'WBE70'; file_put_contents($fixture . '/docs/logo.svg', $body); $manifest['files']['docs/logo.svg']['sha256'] = hash('sha256', $body); file_put_contents($fixture . '/release/assets.json', json_encode($manifest)); }); } finally { $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($fixture, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST); foreach ($iterator as $item) $item->isDir() ? rmdir($item->getPathname()) : unlink($item->getPathname()); rmdir($fixture); } echo "OK: текущие ресурсы, повреждение/удаление/подмена manifest и состав поставки\n";