Files
WP-LIT-MCP/tests/Unit/Integrations/Divi/Design/PresetAssignmentTest.php
T

342 lines
15 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Design;
use Closure;
use LIT\MCP\Integrations\Divi\Design\PresetAssignment;
use LIT\MCP\Integrations\Divi\Design\PresetBook;
use PHPUnit\Framework\TestCase;
final class PresetAssignmentTest extends TestCase
{
private const PATH = 'items[0]';
/** @var int How often the book closure ran. */
private int $bookCalls = 0;
/** Divi's stored format (formats §3): two module presets, group presets with two names the same ("Doppelt"). */
private static function stored(): array
{
$module = static fn (string $id, string $name, array $attrs = []): array => [
'type' => 'module', 'id' => $id, 'name' => $name, 'moduleName' => 'divi/blurb', 'attrs' => $attrs,
];
$group = static fn (string $id, string $name, string $groupName, string $groupId, array $attrs = []): array => [
'type' => 'group', 'id' => $id, 'name' => $name, 'groupName' => $groupName, 'groupId' => $groupId,
'moduleName' => 'divi/blurb', 'attrs' => $attrs,
];
return [
'module' => ['divi/blurb' => ['default' => '', 'items' => [
'bl00000001' => $module('bl00000001', 'Leistung', [
'title' => ['decoration' => ['font' => ['font' => ['desktop' => ['value' => ['weight' => '700']]]]]],
]),
'bl00000002' => $module('bl00000002', 'Karte'),
'bl00000003' => $module('bl00000003', 'Doppelt'),
'bl00000004' => $module('bl00000004', 'doppelt'),
'ba!d000005' => $module('ba!d000005', 'Kaputt'),
]]],
'group' => [
'divi/font-body' => ['default' => '', 'items' => [
'fb00000001' => $group('fb00000001', 'Fließtext', 'divi/font-body', 'content.decoration.bodyFont'),
'fb00000002' => $group('fb00000002', 'Fließtext groß', 'divi/font-body', 'content.decoration.bodyFont'),
'fb00000003' => $group('fb00000003', 'Doppelt', 'divi/font-body', 'content.decoration.bodyFont'),
'fb00000004' => $group('fb00000004', 'Doppelt', 'divi/font-body', 'content.decoration.bodyFont'),
]],
'divi/spacing' => ['default' => '', 'items' => [
'sp00000001' => $group('sp00000001', 'Abstand Karte', 'divi/spacing', 'module.decoration.spacing'),
]],
'divi/font' => ['default' => '', 'items' => [
'ft00000001' => $group('ft00000001', 'Titelschrift', 'divi/font', 'title.decoration.font'),
]],
],
];
}
private function assignment(?Closure $book = null): PresetAssignment
{
return new PresetAssignment(
$book ?? function (): PresetBook {
++$this->bookCalls;
return PresetBook::fromDivi(self::stored());
},
static fn (string $module): array => $module === 'divi/blurb' ? [
'title.decoration.font' => 'divi/font',
'content.decoration.bodyFont' => 'divi/font-body',
'module.decoration.spacing' => 'divi/spacing',
'button.decoration.spacing' => 'divi/spacing',
] : [],
static fn (string $id): bool => preg_match('/^[0-9a-z]+$/D', $id) === 1
);
}
public function testSingleNameOrIdBecomesAStackOfOne(): void
{
$byName = $this->assignment()->apply('divi/blurb', ['x' => 1], ['preset' => 'LEISTUNG'], self::PATH);
$byId = $this->assignment()->apply('divi/blurb', [], ['preset' => 'bl00000002'], self::PATH);
self::assertSame([], $byName['errors']);
self::assertSame(['x' => 1, 'modulePreset' => ['bl00000001']], $byName['attrs']);
self::assertSame(['modulePreset' => ['bl00000002']], $byId['attrs']);
}
public function testListKeepsTheOrderOfTheStack(): void
{
$result = $this->assignment()->apply(
'divi/blurb',
['modulePreset' => ['alt']],
['preset' => ['Karte', 'bl00000001']],
self::PATH
);
self::assertSame([], $result['errors']);
self::assertSame(['modulePreset' => ['bl00000002', 'bl00000001']], $result['attrs']);
}
public function testNullAndEmptyStringRemoveThePresetWithoutLoadingTheBook(): void
{
foreach ([null, ''] as $preset) {
$result = $this->assignment()->apply(
'divi/blurb',
['modulePreset' => ['bl00000001'], 'builderVersion' => '5.2.1'],
['preset' => $preset],
self::PATH
);
self::assertSame([], $result['errors']);
self::assertSame(['builderVersion' => '5.2.1'], $result['attrs']);
}
self::assertSame(0, $this->bookCalls);
}
public function testSpecWithoutPresetKeysChangesNothing(): void
{
$attrs = ['modulePreset' => ['bl00000001']];
$result = $this->assignment()->apply('divi/blurb', $attrs, ['label' => 'egal'], self::PATH);
self::assertSame(['attrs' => $attrs, 'errors' => []], $result);
self::assertSame(0, $this->bookCalls);
}
public function testStackErrorsLeaveTheStackUntouched(): void
{
$attrs = ['modulePreset' => ['alt']];
$assignment = $this->assignment();
$unknown = $assignment->apply('divi/blurb', $attrs, ['preset' => 'Gibt es nicht'], self::PATH);
self::assertSame(
['items[0].preset' => 'unbekanntes Preset; vorhanden für divi/blurb: Leistung, Karte, Doppelt, doppelt, Kaputt'],
$unknown['errors']
);
self::assertSame($attrs, $unknown['attrs']);
$ambiguous = $assignment->apply('divi/blurb', $attrs, ['preset' => ['Karte', 'Doppelt']], self::PATH);
self::assertSame(
['items[0].preset.1' => 'Preset-Name "Doppelt" ist mehrdeutig; bitte die ID angeben: '
. 'bl00000003, bl00000004.'],
$ambiguous['errors']
);
self::assertSame($attrs, $ambiguous['attrs']);
$duplicate = $assignment->apply('divi/blurb', $attrs, ['preset' => ['Karte', 'bl00000001', 'bl00000002']], self::PATH);
self::assertSame(['items[0].preset.2' => 'Preset "bl00000002" steht mehrfach im Stapel'], $duplicate['errors']);
$invalid = $assignment->apply('divi/blurb', $attrs, ['preset' => 'Kaputt'], self::PATH);
self::assertSame(['items[0].preset' => 'Preset-ID "ba!d000005" ist ungültig'], $invalid['errors']);
self::assertSame($attrs, $invalid['attrs']);
}
public function testStackShapeErrors(): void
{
$assignment = $this->assignment();
$empty = $assignment->apply('divi/blurb', [], ['preset' => []], self::PATH);
self::assertSame(['items[0].preset' => 'leere Liste – null entfernt das Preset'], $empty['errors']);
$tooMany = $assignment->apply('divi/blurb', [], ['preset' => array_fill(0, 11, 'Karte')], self::PATH);
self::assertSame(['items[0].preset' => 'höchstens 10 Presets im Stapel'], $tooMany['errors']);
$notText = $assignment->apply('divi/blurb', [], ['preset' => ['Karte', 5]], self::PATH);
self::assertSame(['items[0].preset.1' => 'Preset-Name oder -ID als Text erwartet'], $notText['errors']);
$object = $assignment->apply('divi/blurb', [], ['preset' => ['a' => 'Karte']], self::PATH);
self::assertSame(['items[0].preset' => 'Text, Liste von Texten oder null erwartet'], $object['errors']);
$number = $assignment->apply('divi/blurb', [], ['preset' => 7], self::PATH);
self::assertSame(['items[0].preset' => 'Text, Liste von Texten oder null erwartet'], $number['errors']);
}
public function testGroupPresetsByShortNameFullNameAndPath(): void
{
$result = $this->assignment()->apply('divi/blurb', ['builderVersion' => '5.2.1'], ['group_presets' => [
'font-body' => 'Fließtext',
'divi/font' => 'ft00000001',
'button.decoration.spacing' => ['Abstand Karte'],
]], self::PATH);
self::assertSame([], $result['errors']);
self::assertSame(
[
'builderVersion' => '5.2.1',
'groupPreset' => [
'content.decoration.bodyFont' => ['presetId' => ['fb00000001'], 'groupName' => 'divi/font-body'],
'title.decoration.font' => ['presetId' => ['ft00000001'], 'groupName' => 'divi/font'],
'button.decoration.spacing' => ['presetId' => ['sp00000001'], 'groupName' => 'divi/spacing'],
],
],
$result['attrs']
);
}
public function testGroupPresetListIsAStackAndOtherGroupsStay(): void
{
$attrs = ['groupPreset' => [
'title.decoration.font' => ['presetId' => ['ft00000001'], 'groupName' => 'divi/font'],
]];
$result = $this->assignment()->apply(
'divi/blurb',
$attrs,
['group_presets' => ['font-body' => ['Fließtext', 'Fließtext groß']]],
self::PATH
);
self::assertSame([], $result['errors']);
self::assertSame(['fb00000001', 'fb00000002'], $result['attrs']['groupPreset']['content.decoration.bodyFont']['presetId']);
self::assertSame($attrs['groupPreset']['title.decoration.font'], $result['attrs']['groupPreset']['title.decoration.font']);
}
public function testNullRemovesTheGroupEntryAndAnEmptyGroupPresetDisappears(): void
{
$attrs = ['groupPreset' => [
'title.decoration.font' => ['presetId' => ['ft00000001'], 'groupName' => 'divi/font'],
'content.decoration.bodyFont' => ['presetId' => ['fb00000001'], 'groupName' => 'divi/font-body'],
]];
$one = $this->assignment()->apply('divi/blurb', $attrs, ['group_presets' => ['font' => null]], self::PATH);
self::assertSame(['content.decoration.bodyFont'], array_keys($one['attrs']['groupPreset']));
$both = $this->assignment()->apply(
'divi/blurb',
$attrs,
['group_presets' => ['font' => null, 'font-body' => null]],
self::PATH
);
self::assertSame([], $both['errors']);
self::assertSame([], $both['attrs']);
}
public function testGroupKeyErrors(): void
{
$assignment = $this->assignment();
$unknown = $assignment->apply('divi/blurb', [], ['group_presets' => ['sizing' => 'X']], self::PATH);
self::assertSame(
['items[0].group_presets.sizing' => 'keine Gruppe "sizing" in divi/blurb; vorhanden: font, font-body, spacing'],
$unknown['errors']
);
$ambiguous = $assignment->apply('divi/blurb', [], ['group_presets' => ['spacing' => 'Abstand Karte']], self::PATH);
self::assertSame(
['items[0].group_presets.spacing' => 'Gruppe "spacing" ist mehrdeutig; bitte den Attributpfad angeben: '
. 'module.decoration.spacing, button.decoration.spacing.'],
$ambiguous['errors']
);
$missing = $assignment->apply('divi/divider', [], ['group_presets' => ['font-body' => 'Fließtext']], self::PATH);
self::assertSame(
['items[0].group_presets.font-body' => 'keine Gruppe "font-body" in divi/divider; vorhanden: (keine)'],
$missing['errors']
);
}
public function testGroupPresetValueErrors(): void
{
$assignment = $this->assignment();
$result = $assignment->apply('divi/blurb', [], ['group_presets' => [
'font-body' => 'Gibt es nicht',
'font' => 7,
'module.decoration.spacing' => [],
]], self::PATH);
self::assertSame(
[
'items[0].group_presets.font-body' => 'unbekanntes Gruppen-Preset "Gibt es nicht" (divi/font-body)',
'items[0].group_presets.font' => 'Text, Liste von Texten oder null erwartet',
'items[0].group_presets.module.decoration.spacing' => 'leere Liste – null entfernt das Gruppen-Preset',
],
$result['errors']
);
self::assertSame([], $result['attrs']);
$ambiguous = $assignment->apply('divi/blurb', [], ['group_presets' => ['font-body' => 'Doppelt']], self::PATH);
self::assertSame(
['items[0].group_presets.font-body' => 'Preset-Name "Doppelt" ist mehrdeutig; bitte die ID angeben: '
. 'fb00000003, fb00000004.'],
$ambiguous['errors']
);
$duplicate = $assignment->apply(
'divi/blurb',
[],
['group_presets' => ['font-body' => ['Fließtext', 'fb00000001']]],
self::PATH
);
self::assertSame(
['items[0].group_presets.font-body' => 'Preset "fb00000001" steht mehrfach im Stapel'],
$duplicate['errors']
);
$shape = $assignment->apply('divi/blurb', [], ['group_presets' => 'font-body'], self::PATH);
self::assertSame(['items[0].group_presets' => 'Objekt Gruppe → Preset erwartet'], $shape['errors']);
}
public function testModulePresetFromAnotherModuleIsUnknown(): void
{
$result = $this->assignment()->apply('divi/text', [], ['preset' => 'Leistung'], self::PATH);
self::assertSame(['items[0].preset' => 'unbekanntes Preset; vorhanden für divi/text: (keine)'], $result['errors']);
}
public function testBookIsLoadedLazilyAndAtMostOnce(): void
{
$assignment = $this->assignment();
self::assertSame(0, $this->bookCalls);
$assignment->apply('divi/blurb', [], ['preset' => 'Karte', 'group_presets' => ['font' => 'Titelschrift']], self::PATH);
$assignment->names();
$assignment->clearOverrides(['modulePreset' => ['bl00000001']]);
$assignment->overrides()->find(['modulePreset' => ['bl00000001']]);
self::assertSame(1, $this->bookCalls);
}
public function testNamesListsEveryPreset(): void
{
$names = $this->assignment()->names();
self::assertSame('Leistung', $names['bl00000001']);
self::assertSame('Fließtext groß', $names['fb00000002']);
self::assertSame('Titelschrift', $names['ft00000001']);
self::assertCount(11, $names);
}
public function testClearOverridesAndOverridesShareTheSameBook(): void
{
$assignment = $this->assignment();
$local = [
'modulePreset' => ['bl00000001'],
'title' => ['decoration' => ['font' => ['font' => ['desktop' => ['value' => ['weight' => '400']]]]]],
];
self::assertSame(
['bl00000001' => ['title.decoration.font.font|desktop|value|weight']],
$assignment->overrides()->find($local)
);
self::assertSame($assignment->overrides(), $assignment->overrides());
self::assertSame(['modulePreset' => ['bl00000001']], $assignment->clearOverrides($local));
}
}