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:
co-authored by
Claude Opus 5.5
parent
c036a92b60
commit
d0d3488df8
@@ -84,16 +84,6 @@ final class CompatibilityMatrixTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testTheWriteFeaturesAreTheWritingCases(): void
|
||||
{
|
||||
self::assertSame(
|
||||
array_values(array_filter(DiviFeature::cases(), static fn (DiviFeature $f): bool => $f->isWrite())),
|
||||
CompatibilityMatrix::writeFeatures()
|
||||
);
|
||||
self::assertContains(DiviFeature::PageWrite, CompatibilityMatrix::writeFeatures());
|
||||
self::assertNotContains(DiviFeature::PageRead, CompatibilityMatrix::writeFeatures());
|
||||
}
|
||||
|
||||
public function testToArrayListsEveryFeatureInCaseOrder(): void
|
||||
{
|
||||
$rows = self::matrix(['tb-write' => [ReleaseState::Incompatible, ['b']]])->toArray();
|
||||
|
||||
@@ -8,9 +8,9 @@ use LIT\MCP\Abilities\ToolRefusal;
|
||||
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
||||
use LIT\MCP\Integrations\Divi\Release\DiviLocked;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseState;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseStatus;
|
||||
use LIT\MCP\Tests\Support\ReleaseMatrices;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use LogicException;
|
||||
|
||||
final class DiviLockedTest extends TestCase
|
||||
{
|
||||
@@ -26,12 +26,11 @@ final class DiviLockedTest extends TestCase
|
||||
self::assertSame(['preset-write'], array_column($payload['features'], 'id'));
|
||||
}
|
||||
|
||||
public function testWithoutFeaturesTheErrorIsTheGeneralWriteLock(): void
|
||||
public function testALockWithoutFeaturesIsAProgrammingError(): void
|
||||
{
|
||||
$status = new ReleaseStatus(ReleaseState::Untested, '5.3.0');
|
||||
$locked = new DiviLocked($status);
|
||||
$this->expectException(LogicException::class);
|
||||
$this->expectExceptionMessage('a Divi lock needs the locked features');
|
||||
|
||||
self::assertSame('Divi 5.3.0 is untested for LIT MCP – write refused', $locked->getMessage());
|
||||
self::assertEquals($status->refusal(), $locked->toError());
|
||||
new DiviLocked(ReleaseMatrices::uniform(ReleaseState::Untested), []);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -145,7 +145,9 @@ final class ReleaseGuardsTest extends TestCase
|
||||
|
||||
public function testTheCheckPageMayBeWrittenWhileProbing(): void
|
||||
{
|
||||
ReleaseGate::useResolver(static fn (): ReleaseStatus => new ReleaseStatus(ReleaseState::Untested, '5.3.0'));
|
||||
ReleaseGate::useResolver(
|
||||
static fn (): ReleaseStatus => ReleaseMatrices::uniform(ReleaseState::Untested, '5.3.0')
|
||||
);
|
||||
Functions\when('wp_update_post')->justReturn(41);
|
||||
Functions\when('update_post_meta')->justReturn(true);
|
||||
Functions\when('get_post_meta')->alias(
|
||||
|
||||
@@ -124,7 +124,7 @@ final class ReleaseResolverTest extends TestCase
|
||||
])->resolve();
|
||||
|
||||
self::assertSame(self::allBut('released'), self::states($status));
|
||||
self::assertTrue($status->writable());
|
||||
self::assertSame([], $status->matrix->unusable());
|
||||
self::assertSame([], $status->problems);
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ final class ReleaseResolverTest extends TestCase
|
||||
self::assertSame(['Seiten: et_x()'], $status->matrix->of(DiviFeature::PageWrite)->problems);
|
||||
self::assertSame(ReleaseState::Incompatible, $status->state);
|
||||
self::assertSame(['Seiten: et_x()', 'Katalog: Konstante X'], $status->problems);
|
||||
self::assertFalse($status->writable());
|
||||
self::assertFalse($status->matrix->of(DiviFeature::PageWrite)->usable());
|
||||
}
|
||||
|
||||
public function testAProblemWithoutFeaturesLocksEveryFeature(): void
|
||||
@@ -181,7 +181,7 @@ final class ReleaseResolverTest extends TestCase
|
||||
self::assertSame(self::allBut('released'), self::states($status));
|
||||
self::assertSame('auto', $status->source);
|
||||
self::assertSame('auto', $status->matrix->of(DiviFeature::PresetWrite)->source);
|
||||
self::assertTrue($status->writable());
|
||||
self::assertSame([], $status->matrix->unusable());
|
||||
}
|
||||
|
||||
/** Review focus 3: the automatic release needs every signature unchanged. */
|
||||
@@ -196,7 +196,7 @@ final class ReleaseResolverTest extends TestCase
|
||||
['Designsystem: x() – Signatur geändert'],
|
||||
$status->matrix->of(DiviFeature::PresetWrite)->problems
|
||||
);
|
||||
self::assertFalse($status->writable());
|
||||
self::assertFalse($status->matrix->of(DiviFeature::PresetWrite)->usable());
|
||||
}
|
||||
|
||||
public function testAMissingReferenceMakesItsFeatureUntestedUnderAutomaticRelease(): void
|
||||
|
||||
@@ -15,52 +15,6 @@ use LogicException;
|
||||
|
||||
final class ReleaseStatusTest extends TestCase
|
||||
{
|
||||
public function testOnlyAReleasedVersionIsWritable(): void
|
||||
{
|
||||
self::assertTrue(ReleaseStatus::released('5.2.1')->writable());
|
||||
self::assertFalse((new ReleaseStatus(ReleaseState::Untested, '5.3.0'))->writable());
|
||||
self::assertFalse((new ReleaseStatus(ReleaseState::Incompatible, '5.3.0', null, ['x']))->writable());
|
||||
}
|
||||
|
||||
public function testUntestedRefusalNamesTheVersionAndTheWayOut(): void
|
||||
{
|
||||
$payload = self::assertToolError(
|
||||
(new ReleaseStatus(ReleaseState::Untested, '5.3.0'))->refusal(),
|
||||
'divi_untested'
|
||||
);
|
||||
|
||||
self::assertSame(
|
||||
'Achtung: Divi 5.3.0 ist auf dieser Website noch nicht für LIT MCP freigegeben. Dieses Werkzeug braucht '
|
||||
. 'Divi-Fähigkeiten, die noch nicht geprüft sind; andere Divi-Werkzeuge laufen weiter. Ein '
|
||||
. 'Administrator kann unter Einstellungen → LIT MCP → Divi die Prüfung ausführen und die Version '
|
||||
. 'freigeben. Es wurde nichts geändert.',
|
||||
$payload['message']
|
||||
);
|
||||
self::assertStringContainsString('ein Werkzeug ohne die betroffene Fähigkeit nutzen', $payload['hint']);
|
||||
self::assertStringContainsString('components → divi → features', $payload['hint']);
|
||||
}
|
||||
|
||||
public function testIncompatibleRefusalListsTheProblems(): void
|
||||
{
|
||||
$status = new ReleaseStatus(ReleaseState::Incompatible, '5.3.0', null, ['Theme Builder: Nachbau von x()']);
|
||||
$payload = self::assertToolError($status->refusal(), 'divi_incompatible');
|
||||
|
||||
self::assertSame(
|
||||
'Divi 5.3.0 hat Stellen geändert, die LIT MCP für dieses Werkzeug nutzt; andere Divi-Werkzeuge laufen '
|
||||
. 'weiter. Die betroffenen Werkzeuge bleiben gesperrt, bis LIT MCP aktualisiert wurde. Es wurde '
|
||||
. 'nichts geändert.',
|
||||
$payload['message']
|
||||
);
|
||||
self::assertSame(['Theme Builder: Nachbau von x()'], $payload['problems']);
|
||||
}
|
||||
|
||||
public function testAReleasedStatusHasNoRefusal(): void
|
||||
{
|
||||
$this->expectException(LogicException::class);
|
||||
|
||||
ReleaseStatus::released('5.2.1')->refusal();
|
||||
}
|
||||
|
||||
public function testToArrayForSiteStatus(): void
|
||||
{
|
||||
$status = new ReleaseStatus(
|
||||
@@ -82,7 +36,7 @@ final class ReleaseStatusTest extends TestCase
|
||||
{
|
||||
$untested = new ReleaseStatus(ReleaseState::Untested, '5.3.0');
|
||||
$broken = new ReleaseStatus(ReleaseState::Incompatible, '5.3.0', null, ['x']);
|
||||
$released = ReleaseStatus::released('5.2.1', ReleaseStatus::SOURCE_DATABASE);
|
||||
$released = ReleaseMatrices::released('5.2.1', ReleaseStatus::SOURCE_DATABASE);
|
||||
|
||||
foreach (DiviFeature::cases() as $feature) {
|
||||
self::assertSame(ReleaseState::Untested, $untested->matrix->of($feature)->state);
|
||||
@@ -106,17 +60,6 @@ final class ReleaseStatusTest extends TestCase
|
||||
self::assertSame('auto', ReleaseStatus::of('5.99.0', CompatibilityMatrix::allReleased('auto'))->source);
|
||||
}
|
||||
|
||||
public function testWritableAsksOnlyTheWritingFeatures(): void
|
||||
{
|
||||
$readLocked = ReleaseMatrices::status([DiviFeature::Catalog, DiviFeature::PageRead]);
|
||||
self::assertSame(ReleaseState::Untested, $readLocked->state);
|
||||
self::assertTrue($readLocked->writable());
|
||||
|
||||
foreach (CompatibilityMatrix::writeFeatures() as $feature) {
|
||||
self::assertFalse(ReleaseMatrices::status([$feature])->writable(), $feature->value);
|
||||
}
|
||||
}
|
||||
|
||||
public function testAMatrixInAnotherStateThanTheStatusIsRefused(): void
|
||||
{
|
||||
$this->expectException(LogicException::class);
|
||||
|
||||
@@ -5,12 +5,14 @@ declare(strict_types=1);
|
||||
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Release;
|
||||
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseGate;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseState;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseStatus;
|
||||
use LIT\MCP\Integrations\Divi\Release\WriteProbe;
|
||||
use LIT\MCP\Integrations\WordPress\Content\ContentComposer;
|
||||
use LIT\MCP\Integrations\WordPress\Render\PageRenderer;
|
||||
use LIT\MCP\Tests\Support\ReleaseMatrices;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
@@ -25,7 +27,7 @@ final class WriteProbeTest extends TestCase
|
||||
{
|
||||
parent::setUp();
|
||||
// The probe must work while Divi is untested – that is when it runs.
|
||||
ReleaseGate::useResolver(static fn (): ReleaseStatus => new ReleaseStatus(ReleaseState::Untested, '5.3.0'));
|
||||
ReleaseGate::useResolver(static fn (): ReleaseStatus => ReleaseMatrices::uniform(ReleaseState::Untested));
|
||||
$this->deleted = [];
|
||||
Functions\when('wp_insert_post')->justReturn(41);
|
||||
Functions\when('get_post')->justReturn(
|
||||
@@ -47,7 +49,7 @@ final class WriteProbeTest extends TestCase
|
||||
$composer = Mockery::mock(ContentComposer::class);
|
||||
$default = static function (int $id, string $type, array $sections): array {
|
||||
// The composer writes through the saver, which asks the gate: the probe must have opened it for 41.
|
||||
ReleaseGate::assertWritable($id);
|
||||
ReleaseGate::assertFeatures(DiviFeature::cases(), $id);
|
||||
|
||||
return ['warnings' => [], 'outline' => ''];
|
||||
};
|
||||
@@ -100,7 +102,7 @@ final class WriteProbeTest extends TestCase
|
||||
self::assertSame(['Schreibtest abgebrochen: Composer kaputt'], $problems);
|
||||
self::assertSame([41], $this->deleted);
|
||||
$this->expectException(\LIT\MCP\Integrations\Divi\Release\DiviLocked::class);
|
||||
ReleaseGate::assertWritable(41);
|
||||
ReleaseGate::assertFeature(DiviFeature::PageWrite, 41);
|
||||
}
|
||||
|
||||
public function testReportsAPageThatCouldNotBeDeleted(): void
|
||||
|
||||
Reference in New Issue
Block a user