feat: VariableArea schreibt globale Variablen mit Divis Stale-Prüfung und behält beim Wiederherstellen spätere Variablen archiviert

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-19 14:10:02 +02:00
co-authored by Claude Sonnet 5.5
parent 2fd03f3900
commit f1f70114f4
2 changed files with 265 additions and 0 deletions
@@ -0,0 +1,159 @@
<?php
declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Design;
use LIT\MCP\Integrations\Divi\Design\GlobalVariablesAdapter;
use LIT\MCP\Integrations\Divi\Design\VariableArea;
use LIT\MCP\Integrations\Divi\Design\VariableBook;
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
use LIT\MCP\Tests\Unit\TestCase;
use Mockery;
final class VariableAreaTest extends TestCase
{
/**
* GlobalVariablesAdapter::read() (stored form, V7): Eckenradius (numbers), Slogan, the archived Alter Slogan
* and the archived empty Leer (strings), and Verlauf (gradients, only passed through).
*
* @return array<string, array<string, array<string, mixed>>>
*/
public static function stored(): array
{
$entry = static fn (string $type, string $id, string $label, string $value, string $order, string $status)
: array => ['id' => $id, 'label' => $label, 'value' => $value, 'order' => $order, 'status' => $status,
'lastUpdated' => '2026-10-01T10:00:00.000Z', 'variableType' => $type];
return [
'numbers' => [
'gvid-radius0001' => $entry('numbers', 'gvid-radius0001', 'Eckenradius', '8px', '1', 'active'),
],
'strings' => [
'gvid-slogan0001' => $entry('strings', 'gvid-slogan0001', 'Slogan', 'Holz mit Herz', '1', 'active'),
'gvid-alt0000001' => $entry('strings', 'gvid-alt0000001', 'Alter Slogan', 'Früher', '', 'archived'),
'gvid-leer000001' => $entry('strings', 'gvid-leer000001', 'Leer', '', '', 'archived'),
],
'gradients' => [
'gvid-verlauf001' => $entry(
'gradients',
'gvid-verlauf001',
'Verlauf',
'linear-gradient(#fff, #000)',
'1',
'active'
),
],
];
}
/**
* A GlobalVariablesAdapter over $stored: save() replaces the inventory like set_global_variables() and notes each
* call (data, expected) in $saves.
*
* @param array<string, array<string, array<string, mixed>>> $stored
* @param list<array{0: array<string, mixed>, 1: array<string, mixed>}> $saves
*/
public static function adapter(array &$stored, array &$saves, bool $manage = true): GlobalVariablesAdapter
{
$variables = Mockery::mock(GlobalVariablesAdapter::class);
$variables->allows('canManage')->andReturn($manage);
$variables->allows('read')->andReturnUsing(static function () use (&$stored): array {
return $stored;
});
$variables->allows('save')->andReturnUsing(
static function (array $data, array $expected) use (&$stored, &$saves): void {
$saves[] = [$data, $expected];
$stored = $data;
}
);
return $variables;
}
public function testAreaReadsThroughTheAdapter(): void
{
$stored = self::stored();
$saves = [];
$area = new VariableArea(self::adapter($stored, $saves));
self::assertSame(['variables', 'Variablen'], [$area->name(), $area->label()]);
self::assertSame(DiviFeature::VariableWrite, $area->feature());
self::assertSame(VariableBook::fromDivi($stored)->data(), $area->raw());
self::assertSame(VariableBook::fromDivi($stored)->rev(), $area->rev($stored));
}
/** Ruling V7: the whole planned inventory, with the inventory read before for Divi's stale check. */
public function testWriteSavesThePlannedInventoryAgainstTheLiveOne(): void
{
$stored = self::stored();
$saves = [];
$area = new VariableArea(self::adapter($stored, $saves));
$planned = self::stored();
$planned['numbers']['gvid-radius0001']['value'] = '12px';
$saved = $area->write($planned, false);
self::assertSame([[VariableBook::fromDivi($planned)->data(), self::stored()]], $saves);
self::assertSame('12px', $saved['numbers']['gvid-radius0001']['value']);
}
/** Ruling V1b: Divi refuses an inventory without a stored ID – later variables stay, archived. */
public function testRestoreKeepsVariablesCreatedAfterTheSnapshotArchived(): void
{
$stored = self::stored();
$stored['numbers']['gvid-neu0000001'] = ['id' => 'gvid-neu0000001', 'label' => 'Neu', 'value' => '4px',
'order' => '2', 'status' => 'active', 'lastUpdated' => '2026-10-19T09:00:00.000Z',
'variableType' => 'numbers'];
$live = $stored;
$saves = [];
$area = new VariableArea(self::adapter($stored, $saves));
$area->restore(VariableBook::fromDivi(self::stored())->data());
self::assertCount(1, $saves);
self::assertSame(
VariableBook::fromDivi($live)->restoredFrom(VariableBook::fromDivi(self::stored()))->data(),
$saves[0][0]
);
self::assertSame($live, $saves[0][1]);
self::assertSame('archived', $saves[0][0]['numbers']['gvid-neu0000001']['status']);
}
public function testVerifyInsistsOnTheSameVariablesStatusAndValues(): void
{
$stored = self::stored();
$saves = [];
$area = new VariableArea(self::adapter($stored, $saves));
$expected = self::stored();
$sanitized = $expected;
$sanitized['strings']['gvid-slogan0001']['value'] = 'Holz mit Herz ';
$missing = $expected;
unset($missing['numbers']['gvid-radius0001']);
$archived = $expected;
$archived['numbers']['gvid-radius0001']['status'] = 'archived';
$emptied = $expected;
$emptied['numbers']['gvid-radius0001']['value'] = '';
self::assertTrue($area->verify($expected, $sanitized));
self::assertFalse($area->verify($expected, $missing));
self::assertFalse($area->verify($expected, $archived));
self::assertFalse($area->verify($expected, $emptied));
}
public function testDifferencesNameTheVariablesDiviChanged(): void
{
$stored = self::stored();
$saves = [];
$area = new VariableArea(self::adapter($stored, $saves));
$expected = self::stored();
$sanitized = $expected;
$sanitized['strings']['gvid-slogan0001']['value'] = 'Holz mit Herz ';
self::assertSame([], $area->differences($expected, $expected));
self::assertSame(
['Divi hat den Wert der Variablen „Slogan“ beim Speichern bereinigt.'],
$area->differences($expected, $sanitized)
);
}
}