feat: ThemeOptionsRestorePlanner – Snapshot theme_options ersetzt die Whitelist, nennt zurückgesetzte Optionen

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-19 17:58:04 +02:00
co-authored by Claude Sonnet 5.5
parent 449ec5c33f
commit 2e3b740260
2 changed files with 173 additions and 0 deletions
@@ -0,0 +1,102 @@
<?php
declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Design;
use Brain\Monkey\Functions;
use LIT\MCP\Integrations\Divi\Design\DesignPlan;
use LIT\MCP\Integrations\Divi\Design\DesignSystemWriter;
use LIT\MCP\Integrations\Divi\Design\ThemeOptionBook;
use LIT\MCP\Integrations\Divi\Design\ThemeOptionDiff;
use LIT\MCP\Integrations\Divi\Design\ThemeOptionsArea;
use LIT\MCP\Integrations\Divi\Design\ThemeOptionSpec;
use LIT\MCP\Integrations\Divi\Design\ThemeOptionsRestorePlanner;
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
use LIT\MCP\Tests\Unit\TestCase;
use Mockery;
final class ThemeOptionsRestorePlannerTest extends TestCase
{
public const SNAPSHOT_ID = 'theme_options-20261016T100000Z-aaaaaa';
/** @return array<string, int|float|string|false> The options now: larger text, a gutter set after the snapshot. */
public static function current(): array
{
return ['body_font_size' => 18, 'gutter_width' => 2];
}
/** @return array<string, int|float|string|false> The snapshot: body font and text size 16, no gutter. */
public static function snapshot(): array
{
return ['body_font' => 'Open Sans', 'body_font_size' => 16];
}
private static function planner(bool $customize = true): ThemeOptionsRestorePlanner
{
$stored = [];
$writes = [];
$writer = Mockery::mock(DesignSystemWriter::class);
$writer->allows('canUseVisualBuilder')->andReturn(true);
return new ThemeOptionsRestorePlanner(
$writer,
ThemeOptionsAreaTest::adapter($stored, $writes, null, $customize)
);
}
public function testAreaFeaturesAndDesignArea(): void
{
$planner = self::planner();
self::assertSame('theme_options', $planner->area());
self::assertSame([DiviFeature::ThemeOptionRead, DiviFeature::ThemeOptionWrite], $planner->features());
self::assertInstanceOf(ThemeOptionsArea::class, $planner->designArea());
}
/** Ruling W11: the rights of lit/divi-theme-options-update. */
public function testNeedsTheThemeOptionRights(): void
{
Functions\when('current_user_can')->justReturn(true);
self::assertNull(self::planner()->rights());
self::assertToolError(self::planner(false)->rights(), 'forbidden');
Functions\when('current_user_can')->justReturn(false);
self::assertToolError(self::planner()->rights(), 'forbidden');
}
/** Ruling W6: the snapshot replaces the whole whitelist – keys it lacks return to Divi's default. */
public function testTheSnapshotReplacesEveryOptionAndNamesTheResetOnes(): void
{
$plan = self::planner()->plan(self::current(), self::snapshot(), self::SNAPSHOT_ID);
self::assertInstanceOf(DesignPlan::class, $plan);
self::assertTrue($plan->mayRemove);
self::assertNull($plan->usages);
self::assertSame(ThemeOptionBook::fromDivi(self::snapshot())->data(), $plan->raw);
self::assertSame(
[['body_font', 'added'], ['body_font_size', 'changed'], ['gutter_width', 'reset']],
array_map(static fn (array $row): array => [$row['key'], $row['action']], $plan->diff)
);
self::assertSame(
'Snapshot ' . self::SNAPSHOT_ID . ' wiederherstellen – ' . ThemeOptionDiff::summary($plan->diff),
$plan->summary
);
self::assertSame([
ThemeOptionsArea::SITE_WIDE,
sprintf(
'Theme-Optionen, die im Snapshot nicht gesetzt sind, kehren zum Divi-Standard zurück („%s“).',
ThemeOptionSpec::definition('gutter_width')['label']
),
], $plan->warnings);
}
public function testTheSameOptionsAreNoChange(): void
{
$plan = self::planner()->plan(self::snapshot(), self::snapshot(), self::SNAPSHOT_ID);
self::assertInstanceOf(DesignPlan::class, $plan);
self::assertTrue($plan->isEmpty());
self::assertSame([], $plan->warnings);
}
}