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
@@ -10,7 +10,10 @@ use LIT\MCP\Integrations\Divi\Release\FeatureStatus;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseState;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseStatus;
|
||||
|
||||
/** Release statuses for tests: every feature released except the named ones. */
|
||||
/**
|
||||
* Release statuses for tests, built the way production builds them (ReleaseStatus::of() with a matrix): every feature
|
||||
* released except the named ones, all released, or all in one state.
|
||||
*/
|
||||
final class ReleaseMatrices
|
||||
{
|
||||
/** @param list<DiviFeature> $locked */
|
||||
@@ -38,4 +41,27 @@ final class ReleaseMatrices
|
||||
): ReleaseStatus {
|
||||
return ReleaseStatus::of($version, self::matrix($locked, $state));
|
||||
}
|
||||
|
||||
/**
|
||||
* Every feature released from $source (DiviReleases::TESTED = code, ReleaseStore = database, auto).
|
||||
*
|
||||
* @param array<string, mixed>|null $release The database entry of a SOURCE_DATABASE release.
|
||||
*/
|
||||
public static function released(
|
||||
string $version = '5.2.1',
|
||||
string $source = ReleaseStatus::SOURCE_CODE,
|
||||
?array $release = null
|
||||
): ReleaseStatus {
|
||||
return ReleaseStatus::of($version, CompatibilityMatrix::allReleased($source), $release);
|
||||
}
|
||||
|
||||
/**
|
||||
* Every feature in $state with $problems (an unreleased or broken Divi as a whole).
|
||||
*
|
||||
* @param list<string> $problems
|
||||
*/
|
||||
public static function uniform(ReleaseState $state, string $version = '5.3.0', array $problems = []): ReleaseStatus
|
||||
{
|
||||
return ReleaseStatus::of($version, CompatibilityMatrix::uniform($state, $problems));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,12 @@ use LIT\MCP\Integrations\Divi\Release\DiviFeatureGate;
|
||||
use LIT\MCP\Integrations\Divi\Release\DiviLocked;
|
||||
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\RequiresDiviFeatures;
|
||||
use LIT\MCP\Integrations\Integration;
|
||||
use LIT\MCP\Integrations\IntegrationRegistry;
|
||||
use LIT\MCP\Server\RequestContext;
|
||||
use LIT\MCP\Tests\Support\DiviFeatureFixtures;
|
||||
use LIT\MCP\Tests\Support\ReleaseMatrices;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
@@ -281,7 +281,10 @@ final class AbilityRegistrarTest extends TestCase
|
||||
|
||||
public function testALockThrownInsideAWriteBecomesTheLockError(): void
|
||||
{
|
||||
$locked = new DiviLocked(new ReleaseStatus(ReleaseState::Incompatible, '5.3.0', null, ['x']));
|
||||
$locked = new DiviLocked(
|
||||
ReleaseMatrices::uniform(ReleaseState::Incompatible, '5.3.0', ['x']),
|
||||
[DiviFeature::PageWrite]
|
||||
);
|
||||
$ability = $this->ability();
|
||||
$ability->allows('execute')->andThrow(WriteFailed::rolledBack('Nicht gespeichert.', $locked));
|
||||
|
||||
@@ -302,7 +305,7 @@ final class AbilityRegistrarTest extends TestCase
|
||||
|
||||
public function testAPartialWriteStaysPartialEvenWithALockInside(): void
|
||||
{
|
||||
$locked = new DiviLocked(new ReleaseStatus(ReleaseState::Untested, '5.3.0'));
|
||||
$locked = new DiviLocked(ReleaseMatrices::uniform(ReleaseState::Untested, '5.3.0'), [DiviFeature::PageWrite]);
|
||||
$ability = $this->ability();
|
||||
$ability->allows('execute')->andThrow(WriteFailed::partial('Teilweise gespeichert.', $locked));
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ use LIT\MCP\Plugin;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\FeatureFakeTool;
|
||||
use LIT\MCP\Tests\Support\MatrixFixtures;
|
||||
use LIT\MCP\Tests\Support\ReleaseMatrices;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use WP_Post;
|
||||
@@ -197,7 +198,7 @@ final class DiviTabTest extends TestCase
|
||||
|
||||
public function testUntestedWithAFreshGreenReportOffersTheRelease(): void
|
||||
{
|
||||
$html = $this->rendered(new ReleaseStatus(ReleaseState::Untested, '5.3.0'), self::report());
|
||||
$html = $this->rendered(ReleaseMatrices::uniform(ReleaseState::Untested), self::report());
|
||||
|
||||
self::assertStringContainsString('ungetestet', $html);
|
||||
self::assertStringContainsString('Prüfung starten', $html);
|
||||
@@ -207,9 +208,9 @@ final class DiviTabTest extends TestCase
|
||||
|
||||
public function testCheckButtonSaysWhatItDoesAndLeadsWhileNothingElseCanBeDone(): void
|
||||
{
|
||||
$stale = $this->rendered(new ReleaseStatus(ReleaseState::Untested, '5.3.0'), self::report(true, '5.2.9'));
|
||||
$fresh = $this->rendered(new ReleaseStatus(ReleaseState::Untested, '5.3.0'), self::report());
|
||||
$released = $this->rendered(ReleaseStatus::released('5.3.0'), self::report());
|
||||
$stale = $this->rendered(ReleaseMatrices::uniform(ReleaseState::Untested), self::report(true, '5.2.9'));
|
||||
$fresh = $this->rendered(ReleaseMatrices::uniform(ReleaseState::Untested), self::report());
|
||||
$released = $this->rendered(ReleaseMatrices::released('5.3.0'), self::report());
|
||||
|
||||
foreach ([$stale, $fresh, $released] as $html) {
|
||||
self::assertStringContainsString('legt eine private Testseite an', $html);
|
||||
@@ -222,7 +223,7 @@ final class DiviTabTest extends TestCase
|
||||
|
||||
public function testUntestedWithAStaleReportAsksForANewCheck(): void
|
||||
{
|
||||
$html = $this->rendered(new ReleaseStatus(ReleaseState::Untested, '5.3.0'), self::report(true, '5.2.9'));
|
||||
$html = $this->rendered(ReleaseMatrices::uniform(ReleaseState::Untested), self::report(true, '5.2.9'));
|
||||
|
||||
self::assertStringNotContainsString('Divi 5.3.0 freigeben', $html);
|
||||
self::assertStringContainsString('Prüfung erneut ausführen', $html);
|
||||
@@ -230,7 +231,7 @@ final class DiviTabTest extends TestCase
|
||||
|
||||
public function testReleasedFromCodeOffersNeitherReleaseNorWithdrawal(): void
|
||||
{
|
||||
$html = $this->rendered(ReleaseStatus::released('5.3.0'), self::report());
|
||||
$html = $this->rendered(ReleaseMatrices::released('5.3.0'), self::report());
|
||||
|
||||
self::assertStringContainsString('freigegeben', $html);
|
||||
self::assertStringContainsString('im Plugin als getestet hinterlegt', $html);
|
||||
@@ -240,7 +241,7 @@ final class DiviTabTest extends TestCase
|
||||
|
||||
public function testAnAutomaticReleaseSaysSoAndOffersNeitherReleaseNorWithdrawal(): void
|
||||
{
|
||||
$html = $this->rendered(ReleaseStatus::released('5.99.0', ReleaseStatus::SOURCE_AUTO), self::report());
|
||||
$html = $this->rendered(ReleaseMatrices::released('5.99.0', ReleaseStatus::SOURCE_AUTO), self::report());
|
||||
|
||||
self::assertStringContainsString('Automatisch freigegeben', $html);
|
||||
self::assertStringNotContainsString('freigeben</button>', $html);
|
||||
@@ -249,7 +250,7 @@ final class DiviTabTest extends TestCase
|
||||
|
||||
public function testADatabaseReleaseCanBeWithdrawn(): void
|
||||
{
|
||||
$status = new ReleaseStatus(ReleaseState::Released, '5.3.0', ReleaseStatus::SOURCE_DATABASE, [], [
|
||||
$status = ReleaseMatrices::released('5.3.0', ReleaseStatus::SOURCE_DATABASE, [
|
||||
'released_at' => '2026-10-01T08:00:00+00:00', 'user_id' => 1,
|
||||
]);
|
||||
|
||||
@@ -287,7 +288,7 @@ final class DiviTabTest extends TestCase
|
||||
public function testIncompatibleListsTheProblems(): void
|
||||
{
|
||||
$html = $this->rendered(
|
||||
new ReleaseStatus(ReleaseState::Incompatible, '5.3.0', null, ['Theme Builder: Nachbau von x() – y']),
|
||||
ReleaseMatrices::uniform(ReleaseState::Incompatible, '5.3.0', ['Theme Builder: Nachbau von x() – y']),
|
||||
null
|
||||
);
|
||||
|
||||
@@ -316,7 +317,7 @@ final class DiviTabTest extends TestCase
|
||||
$tab = $this->tab(self::report(), Mockery::mock(ReleaseStore::class));
|
||||
|
||||
$tab->removeOrphans();
|
||||
$html = $this->rendered(ReleaseStatus::released('5.3.0'), self::report(), $tab);
|
||||
$html = $this->rendered(ReleaseMatrices::released('5.3.0'), self::report(), $tab);
|
||||
|
||||
self::assertStringContainsString('Liegengebliebene Prüfseiten gelöscht: 51', $html);
|
||||
}
|
||||
@@ -326,7 +327,7 @@ final class DiviTabTest extends TestCase
|
||||
Functions\expect('get_posts')->never();
|
||||
Functions\expect('wp_delete_post')->never();
|
||||
|
||||
$html = $this->rendered(ReleaseStatus::released('5.3.0'), self::report());
|
||||
$html = $this->rendered(ReleaseMatrices::released('5.3.0'), self::report());
|
||||
|
||||
self::assertStringNotContainsString('Liegengebliebene Prüfseiten', $html);
|
||||
}
|
||||
@@ -367,7 +368,7 @@ final class DiviTabTest extends TestCase
|
||||
new FeatureStatus(DiviFeature::Catalog, ReleaseState::Untested, [], null),
|
||||
]);
|
||||
|
||||
return new ReleaseStatus(ReleaseState::Incompatible, '5.3.0', null, [], null, matrix: $matrix);
|
||||
return ReleaseStatus::of('5.3.0', $matrix);
|
||||
}
|
||||
|
||||
public function testTheFeatureTableShowsStateSourceProblemsAndTools(): void
|
||||
@@ -403,11 +404,11 @@ final class DiviTabTest extends TestCase
|
||||
|
||||
public function testTheTableNamesEverySourceInWords(): void
|
||||
{
|
||||
$code = $this->rendered(ReleaseStatus::released('5.3.0'), null);
|
||||
$code = $this->rendered(ReleaseMatrices::released('5.3.0'), null);
|
||||
$database = $this->rendered(
|
||||
new ReleaseStatus(ReleaseState::Released, '5.3.0', ReleaseStatus::SOURCE_DATABASE, [], [
|
||||
ReleaseStatus::of('5.3.0', MatrixFixtures::released('database'), [
|
||||
'released_at' => '2026-10-01T08:00:00+00:00', 'user_id' => 1,
|
||||
], matrix: MatrixFixtures::released('database')),
|
||||
]),
|
||||
self::report()
|
||||
);
|
||||
|
||||
@@ -417,7 +418,7 @@ final class DiviTabTest extends TestCase
|
||||
|
||||
public function testTheTabExplainsTheAutomationAndTheFilter(): void
|
||||
{
|
||||
$html = $this->rendered(ReleaseStatus::released('5.3.0'), null);
|
||||
$html = $this->rendered(ReleaseMatrices::released('5.3.0'), null);
|
||||
|
||||
self::assertStringContainsString('gibt LIT MCP jede Fähigkeit einzeln frei', $html);
|
||||
self::assertStringContainsString('<code>lit_mcp_divi_auto_release</code>', $html);
|
||||
@@ -429,11 +430,7 @@ final class DiviTabTest extends TestCase
|
||||
public function testTheTabNoLongerSaysWritingIsLockedAsAWhole(): void
|
||||
{
|
||||
$untested = $this->rendered(
|
||||
new ReleaseStatus(
|
||||
ReleaseState::Untested,
|
||||
'5.3.0',
|
||||
matrix: MatrixFixtures::with(DiviFeature::Catalog, ReleaseState::Untested)
|
||||
),
|
||||
ReleaseStatus::of('5.3.0', MatrixFixtures::with(DiviFeature::Catalog, ReleaseState::Untested)),
|
||||
null
|
||||
);
|
||||
$incompatible = $this->rendered(self::mixedStatus(), null);
|
||||
@@ -450,9 +447,9 @@ final class DiviTabTest extends TestCase
|
||||
$matrix = MatrixFixtures::released('database', [
|
||||
new FeatureStatus(DiviFeature::PageWrite, ReleaseState::Incompatible, ['Seiten: x() fehlt'], null),
|
||||
]);
|
||||
$status = new ReleaseStatus(ReleaseState::Incompatible, '5.3.0', ReleaseStatus::SOURCE_DATABASE, [], [
|
||||
$status = ReleaseStatus::of('5.3.0', $matrix, [
|
||||
'released_at' => '2026-10-01T08:00:00+00:00', 'user_id' => 1,
|
||||
], matrix: $matrix);
|
||||
]);
|
||||
|
||||
self::assertStringContainsString('Freigabe zurückziehen', $this->rendered($status, self::report()));
|
||||
}
|
||||
@@ -495,7 +492,7 @@ final class DiviTabTest extends TestCase
|
||||
|
||||
public function testNoNoticeWhileEveryFeatureIsUsable(): void
|
||||
{
|
||||
self::assertSame('', $this->notice(ReleaseStatus::released('5.3.0')));
|
||||
self::assertSame('', $this->notice(ReleaseMatrices::released('5.3.0')));
|
||||
}
|
||||
|
||||
public function testNoNoticeForUsersWithoutManageOptions(): void
|
||||
|
||||
@@ -18,6 +18,7 @@ use LIT\MCP\Integrations\Divi\Release\ReleaseResolver;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseState;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseStatus;
|
||||
use LIT\MCP\Tests\Support\MatrixFixtures;
|
||||
use LIT\MCP\Tests\Support\ReleaseMatrices;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
@@ -354,7 +355,7 @@ final class DiviCheckCommandTest extends TestCase
|
||||
ReleaseGate::useResolver(static function () use (&$order): ReleaseStatus {
|
||||
$order[] = 'resolve';
|
||||
|
||||
return ReleaseStatus::released('5.3.0');
|
||||
return ReleaseMatrices::released('5.3.0');
|
||||
});
|
||||
|
||||
$this->command()->run([]);
|
||||
|
||||
@@ -374,7 +374,9 @@ final class DesignChangeTest extends TestCase
|
||||
|
||||
public function testLockedDiviWritesNoSnapshot(): void
|
||||
{
|
||||
ReleaseGate::useResolver(static fn (): ReleaseStatus => new ReleaseStatus(ReleaseState::Untested, '5.16.0'));
|
||||
ReleaseGate::useResolver(
|
||||
static fn (): ReleaseStatus => ReleaseMatrices::uniform(ReleaseState::Untested, '5.16.0')
|
||||
);
|
||||
$stored = ['v' => 1];
|
||||
$area = self::area($stored);
|
||||
$snapshots = Mockery::mock(SnapshotStore::class);
|
||||
|
||||
@@ -12,6 +12,7 @@ use LIT\MCP\Integrations\Divi\Release\Manifest;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseGate;
|
||||
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;
|
||||
|
||||
final class DesignSystemWriterTest extends TestCase
|
||||
@@ -38,7 +39,9 @@ final class DesignSystemWriterTest extends TestCase
|
||||
|
||||
public function testWritesNeedAReleasedDivi(): void
|
||||
{
|
||||
ReleaseGate::useResolver(static fn (): ReleaseStatus => new ReleaseStatus(ReleaseState::Untested, '5.16.0'));
|
||||
ReleaseGate::useResolver(
|
||||
static fn (): ReleaseStatus => ReleaseMatrices::uniform(ReleaseState::Untested, '5.16.0')
|
||||
);
|
||||
|
||||
$this->expectException(DiviLocked::class);
|
||||
|
||||
|
||||
@@ -18,10 +18,11 @@ use LIT\MCP\Integrations\Divi\Design\PresetUsageQuery;
|
||||
use LIT\MCP\Integrations\Divi\Design\SnapshotStore;
|
||||
use LIT\MCP\Integrations\Divi\Library\GlobalUsages;
|
||||
use LIT\MCP\Integrations\Divi\Library\UsageReport;
|
||||
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\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\ReleaseMatrices;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use Mockery\MockInterface;
|
||||
@@ -378,11 +379,14 @@ final class DiviDesignDetachAbilityTest extends TestCase
|
||||
{
|
||||
return [
|
||||
'rolled back' => [WriteFailed::rolledBack('Seite 12 nicht gespeichert.'), 'write_failed'],
|
||||
'Divi locked' => [new DiviLocked(new ReleaseStatus(ReleaseState::Untested, '5.16.0')), 'divi_untested'],
|
||||
'Divi locked' => [new DiviLocked(
|
||||
ReleaseMatrices::uniform(ReleaseState::Untested, '5.16.0'),
|
||||
[DiviFeature::PageWrite]
|
||||
), 'divi_untested'],
|
||||
'Divi locked inside a rollback' => [
|
||||
WriteFailed::rolledBack(
|
||||
'Seite 12 nicht gespeichert.',
|
||||
new DiviLocked(new ReleaseStatus(ReleaseState::Untested, '5.16.0'))
|
||||
new DiviLocked(ReleaseMatrices::uniform(ReleaseState::Untested, '5.16.0'), [DiviFeature::PageWrite])
|
||||
),
|
||||
'divi_untested',
|
||||
],
|
||||
|
||||
@@ -17,11 +17,12 @@ use LIT\MCP\Integrations\Divi\Library\UsageReport;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviPageLoader;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviSaver;
|
||||
use LIT\MCP\Integrations\Divi\Pages\SaveScope;
|
||||
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\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\LibraryFixtures;
|
||||
use LIT\MCP\Tests\Support\ReleaseMatrices;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use Throwable;
|
||||
@@ -456,7 +457,9 @@ final class PageRewriterTest extends TestCase
|
||||
public function testLockedDiviBeforeTheFirstPageIsThrown(): void
|
||||
{
|
||||
$rewriter = $this->rewriter([self::page(101, self::layout(self::BUTTON))]);
|
||||
$this->failures = [new DiviLocked(new ReleaseStatus(ReleaseState::Untested, '5.16.0'))];
|
||||
$this->failures = [
|
||||
new DiviLocked(ReleaseMatrices::uniform(ReleaseState::Untested, '5.16.0'), [DiviFeature::PageWrite]),
|
||||
];
|
||||
|
||||
$this->expectException(DiviLocked::class);
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ use LIT\MCP\Integrations\Divi\Release\ReleaseState;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseStatus;
|
||||
use LIT\MCP\Tests\Support\FeatureFakeTool;
|
||||
use LIT\MCP\Tests\Support\MatrixFixtures;
|
||||
use LIT\MCP\Tests\Support\ReleaseMatrices;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
|
||||
@@ -83,14 +84,7 @@ final class DiviEnvironmentComponentTest extends TestCase
|
||||
'auto',
|
||||
'Seiten: Signatur von et_pb_x() geändert'
|
||||
);
|
||||
ReleaseGate::useResolver(static fn (): ReleaseStatus => new ReleaseStatus(
|
||||
ReleaseState::Incompatible,
|
||||
'5.3.0',
|
||||
null,
|
||||
[],
|
||||
null,
|
||||
matrix: $matrix
|
||||
));
|
||||
ReleaseGate::useResolver(static fn (): ReleaseStatus => ReleaseStatus::of('5.3.0', $matrix));
|
||||
$overview = new FeatureOverview(static fn (): array => [
|
||||
new FeatureFakeTool('lit/divi-outline', true, [DiviFeature::PageRead]),
|
||||
new FeatureFakeTool('lit/divi-insert', true, [DiviFeature::PageRead, DiviFeature::PageWrite]),
|
||||
@@ -119,7 +113,7 @@ final class DiviEnvironmentComponentTest extends TestCase
|
||||
ReleaseGate::useResolver(static function () use (&$calls): ReleaseStatus {
|
||||
++$calls;
|
||||
|
||||
return ReleaseStatus::released('5.3.0');
|
||||
return ReleaseMatrices::released('5.3.0');
|
||||
});
|
||||
$component = new DiviEnvironmentComponent(new DiviCompatibility([]));
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,8 +11,7 @@ use LIT\MCP\Abilities\WriteFailed;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviContentComposer;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviSaver;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseState;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseStatus;
|
||||
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
||||
use LIT\MCP\Integrations\WordPress\Content\ContentComposer;
|
||||
use LIT\MCP\Integrations\WordPress\Content\ContentCreateAbility;
|
||||
use LIT\MCP\Integrations\WordPress\Content\NewDraft;
|
||||
@@ -20,6 +19,7 @@ use LIT\MCP\Integrations\WordPress\Content\PostWriter;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Tests\Support\DiviWriterFixture;
|
||||
use LIT\MCP\Tests\Support\FakeChangeLog;
|
||||
use LIT\MCP\Tests\Support\ReleaseMatrices;
|
||||
use LIT\MCP\Tests\Support\SchemaFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
@@ -228,7 +228,7 @@ final class ContentCreateDiviTest extends TestCase
|
||||
*/
|
||||
public function testLockedDiviRefusesBeforeTheDraftExists(): void
|
||||
{
|
||||
$refusal = (new ReleaseStatus(ReleaseState::Untested, '5.3.0'))->refusal();
|
||||
$refusal = ReleaseMatrices::status([DiviFeature::PageWrite])->refusalFor([DiviFeature::PageWrite]);
|
||||
Functions\expect('wp_insert_post')->never();
|
||||
|
||||
$result = $this->ability($this->composer(true, true, $refusal))->execute(self::INPUT);
|
||||
|
||||
Reference in New Issue
Block a user