refactor: Übergangs-API der Gesamtsperre entfernt (assertWritable, writable, refusal, writeFeatures, released); DiviLocked verlangt die gesperrten Fähigkeiten, Tests bauen Zustände über ReleaseMatrices

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-18 22:53:00 +02:00
co-authored by Claude Opus 5.5
parent c036a92b60
commit d0d3488df8
21 changed files with 129 additions and 239 deletions
@@ -5,7 +5,6 @@ declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Release;
use LIT\MCP\Abilities\WriteFailed;
use LIT\MCP\Integrations\Divi\Release\CompatibilityMatrix;
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
use LIT\MCP\Integrations\Divi\Release\DiviLocked;
use LIT\MCP\Integrations\Divi\Release\ReleaseGate;
@@ -19,15 +18,13 @@ final class ReleaseGateTest extends TestCase
{
private function untested(): void
{
ReleaseGate::useResolver(static fn (): ReleaseStatus => new ReleaseStatus(ReleaseState::Untested, '5.3.0'));
ReleaseGate::useResolver(static fn (): ReleaseStatus => ReleaseMatrices::uniform(ReleaseState::Untested));
}
public function testTheTestCaseDefaultReleasesEveryFeature(): void
{
self::assertTrue(ReleaseGate::status()->writable());
self::assertSame([], ReleaseGate::status()->matrix->unusable());
ReleaseGate::assertWritable(7);
ReleaseGate::assertFeatures(DiviFeature::cases());
ReleaseGate::assertFeatures(DiviFeature::cases(), 7);
}
public function testFeatureReadsTheMatrixOfThisRequest(): void
@@ -74,34 +71,12 @@ final class ReleaseGateTest extends TestCase
}
}
public function testAssertWritableNeedsEveryWritingFeature(): void
{
ReleaseGate::useResolver(static fn (): ReleaseStatus => ReleaseMatrices::status([DiviFeature::Catalog]));
ReleaseGate::assertWritable();
ReleaseGate::useResolver(static fn (): ReleaseStatus => ReleaseMatrices::status([DiviFeature::LibraryWrite]));
try {
ReleaseGate::assertWritable();
self::fail('a locked writing feature must refuse');
} catch (DiviLocked $locked) {
self::assertSame([DiviFeature::LibraryWrite], $locked->features);
}
ReleaseGate::useResolver(static fn (): ReleaseStatus => new ReleaseStatus(ReleaseState::Untested, '5.3.0'));
try {
ReleaseGate::assertWritable();
self::fail('an untested Divi must lock writes');
} catch (DiviLocked $locked) {
self::assertSame(CompatibilityMatrix::writeFeatures(), $locked->features);
}
}
public function testAssertWritableThrowsTheLockWithTheStatus(): void
public function testAssertFeatureThrowsTheLockWithTheStatus(): void
{
$this->untested();
try {
ReleaseGate::assertWritable(7);
ReleaseGate::assertFeature(DiviFeature::PageWrite, 7);
self::fail('an untested Divi must lock writes');
} catch (DiviLocked $locked) {
self::assertSame('5.3.0', $locked->status->version);
@@ -114,20 +89,24 @@ final class ReleaseGateTest extends TestCase
$this->untested();
$result = ReleaseGate::whileProbing(41, static function (): string {
ReleaseGate::assertWritable(41);
ReleaseGate::assertFeatures(DiviFeature::cases(), 41);
return 'written';
});
self::assertSame('written', $result);
foreach ([static fn () => ReleaseGate::whileProbing(41, static fn () => ReleaseGate::assertWritable(42)),
static fn () => ReleaseGate::whileProbing(41, static fn () => ReleaseGate::assertWritable()),
foreach ([static fn () => ReleaseGate::whileProbing(41, static fn () => ReleaseGate::assertFeatures(
DiviFeature::cases(),
42
)),
static fn () => ReleaseGate::whileProbing(41, static fn () => ReleaseGate::assertFeatures(
DiviFeature::cases()
)),
static fn () => ReleaseGate::whileProbing(41, static fn () => ReleaseGate::assertFeature(
DiviFeature::PageWrite,
42
)),
static fn () => ReleaseGate::assertWritable(41)] as $attempt) {
static fn () => ReleaseGate::assertFeature(DiviFeature::PageWrite, 41)] as $attempt) {
try {
$attempt();
self::fail('only post 41, only while probing');
@@ -149,7 +128,7 @@ final class ReleaseGateTest extends TestCase
}
$this->expectException(DiviLocked::class);
ReleaseGate::assertWritable(41);
ReleaseGate::assertFeature(DiviFeature::PageWrite, 41);
}
public function testStatusIsComputedOncePerRequestUntilForgotten(): void
@@ -158,7 +137,7 @@ final class ReleaseGateTest extends TestCase
ReleaseGate::useResolver(static function () use (&$calls): ReleaseStatus {
++$calls;
return ReleaseStatus::released('5.2.1');
return ReleaseMatrices::released('5.2.1');
});
ReleaseGate::status();
@@ -198,7 +177,7 @@ final class ReleaseGateTest extends TestCase
public function testFindsTheLockInsideAWrappedFailure(): void
{
$locked = new DiviLocked(new ReleaseStatus(ReleaseState::Untested, '5.3.0'));
$locked = new DiviLocked(ReleaseMatrices::uniform(ReleaseState::Untested, '5.3.0'), [DiviFeature::PageWrite]);
$wrapped = WriteFailed::rolledBack('Nicht gespeichert.', new RuntimeException('draft', 0, $locked));
self::assertSame($locked, DiviLocked::in($wrapped));