feat: Divi-Fähigkeiten (DiviFeature, Requirement, ConstantRequirement) an Call, Mirror und Manifest; alle acht Adapter getaggt; Tests für Vollständigkeit und die gepinnte Zuordnung
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
e6e0f914ba
commit
392fe7c569
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Release;
|
||||
|
||||
use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
||||
use LIT\MCP\Integrations\Divi\Design\DesignSystemWriter;
|
||||
use LIT\MCP\Integrations\Divi\Library\DiviLibraryStore;
|
||||
use LIT\MCP\Integrations\Divi\Library\DiviRoles;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviPages;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DynamicContentMap;
|
||||
use LIT\MCP\Integrations\Divi\Release\DiviAdapters;
|
||||
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
||||
use LIT\MCP\Integrations\Divi\Release\Mirror;
|
||||
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
||||
use LIT\MCP\Integrations\Divi\ThemeBuilder\DiviThemeBuilder;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Every manifest entry of every adapter names the Divi features it serves (D2 of the plan "Divi-Fähigkeiten"), and
|
||||
* the assignment is pinned here: a changed tag shows up in review as a changed row of this table.
|
||||
*/
|
||||
final class DiviFeatureAssignmentTest extends TestCase
|
||||
{
|
||||
/** Adapter => requirement ("Nachbau " before a mirror's label) => features (sorted values). */
|
||||
private const EXPECTED = [
|
||||
DiviPages::class => [
|
||||
'ET_Core_PageResource::remove_static_resources()' => ['page-write', 'tb-write'],
|
||||
'et_builder_get_public_post_types()' => ['page-write'],
|
||||
'Nachbau SyncToServerController::update()' => ['page-write'],
|
||||
],
|
||||
DiviLibraryStore::class => [
|
||||
'GlobalLayout::is_global_layout_template()' => ['library-read', 'library-write'],
|
||||
'Nachbau et_pb_submit_layout()' => ['library-write'],
|
||||
],
|
||||
DiviRoles::class => [
|
||||
'et_pb_is_allowed()' => ['roles'],
|
||||
],
|
||||
DiviThemeBuilder::class => [
|
||||
'et_theme_builder_get_theme_builder_post_id()' => ['tb-read', 'tb-write'],
|
||||
'et_theme_builder_get_theme_builder_template_ids()' => ['tb-read'],
|
||||
'et_theme_builder_get_template()' => ['tb-read'],
|
||||
'et_theme_builder_insert_layout()' => ['tb-write'],
|
||||
'et_theme_builder_store_template()' => ['tb-write'],
|
||||
'et_theme_builder_get_flat_template_settings_options()' => ['tb-read'],
|
||||
'et_theme_builder_clear_wp_cache()' => ['page-write', 'tb-write'],
|
||||
'et_()' => ['tb-write'],
|
||||
'ET_Core_PageResource::remove_static_resources()' => ['page-write', 'tb-write'],
|
||||
'Nachbau et_theme_builder_api_save()' => ['tb-write'],
|
||||
'Nachbau et_theme_builder_store_template()' => ['tb-write'],
|
||||
'Nachbau et_theme_builder_load_template_setting_options()' => ['tb-read', 'tb-write'],
|
||||
],
|
||||
DesignSystemReader::class => [
|
||||
'GlobalData::get_global_colors()' => ['design-read', 'page-read'],
|
||||
'GlobalData::get_global_variables()' => ['design-read', 'page-read'],
|
||||
'GlobalPreset::get_data()' => ['design-read', 'page-read'],
|
||||
],
|
||||
DesignSystemWriter::class => [
|
||||
'GlobalPreset::get_data()' => ['design-read', 'preset-write'],
|
||||
'GlobalPreset::prepare_data()' => ['preset-write'],
|
||||
'GlobalPreset::validate_preset_count()' => ['preset-write'],
|
||||
'GlobalPreset::get_deleted_preset_ids()' => ['preset-write'],
|
||||
'GlobalPreset::remove_preset_from_legacy_option()' => ['preset-write'],
|
||||
'GlobalPreset::save_data()' => ['preset-write'],
|
||||
'Conversion::get_preset_attrs_mapping()' => ['preset-write'],
|
||||
'Conversion::get_preset_attrs()' => ['preset-write'],
|
||||
'GlobalPreset::get_group_preset_default_attr()' => ['catalog', 'preset-write'],
|
||||
'ModuleRegistration::get_module_settings()' => ['catalog', 'preset-write'],
|
||||
'UserRole::can_current_user_use_visual_builder()' => ['preset-write'],
|
||||
'Nachbau GlobalPresetController::sync()' => ['preset-write'],
|
||||
],
|
||||
DiviModules::class => [
|
||||
'ModuleRegistration::get_all_core_modules_metadata()' => ['catalog'],
|
||||
'ModuleRegistration::get_default_attrs()' => ['catalog'],
|
||||
'et_builder_enabled_for_post_type()' => ['catalog'],
|
||||
'Konstante ET_BUILDER_PRODUCT_VERSION' => ['catalog'],
|
||||
],
|
||||
DynamicContentMap::class => [
|
||||
'DynamicContentOptions::get_options()' => ['dynamic-sources'],
|
||||
],
|
||||
];
|
||||
|
||||
public function testEveryRequirementOfEveryAdapterServesAtLeastOneFeature(): void
|
||||
{
|
||||
$bare = [];
|
||||
foreach (DiviAdapters::manifests() as $class => $manifest) {
|
||||
foreach ($manifest->requirements() as $requirement) {
|
||||
$features = $manifest->featuresOf($requirement);
|
||||
if ($features === [] || array_unique($features, SORT_REGULAR) !== $features) {
|
||||
$bare[] = $class . ': ' . $requirement->label();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self::assertSame([], $bare, "Anforderungen ohne (eindeutige) Fähigkeit:\n" . implode("\n", $bare));
|
||||
}
|
||||
|
||||
public function testEveryFeatureIsServedByAtLeastOneRequirement(): void
|
||||
{
|
||||
$served = [];
|
||||
foreach (DiviAdapters::manifests() as $manifest) {
|
||||
foreach ($manifest->requirements() as $requirement) {
|
||||
foreach ($manifest->featuresOf($requirement) as $feature) {
|
||||
$served[$feature->value] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$missing = array_values(array_diff(
|
||||
array_map(static fn (DiviFeature $feature): string => $feature->value, DiviFeature::cases()),
|
||||
array_keys($served)
|
||||
));
|
||||
|
||||
self::assertSame([], $missing, 'Fähigkeiten ohne Anforderung in einem Manifest');
|
||||
}
|
||||
|
||||
public function testTheAssignmentIsThePinnedTable(): void
|
||||
{
|
||||
$actual = [];
|
||||
foreach (DiviAdapters::manifests() as $class => $manifest) {
|
||||
foreach ($manifest->requirements() as $requirement) {
|
||||
$values = array_map(
|
||||
static fn (DiviFeature $feature): string => $feature->value,
|
||||
$manifest->featuresOf($requirement)
|
||||
);
|
||||
sort($values);
|
||||
$name = ($requirement instanceof Mirror ? 'Nachbau ' : '') . $requirement->label();
|
||||
$actual[$class][$name] = $values;
|
||||
}
|
||||
}
|
||||
|
||||
self::assertSame(self::EXPECTED, $actual);
|
||||
self::assertSame(array_keys(self::EXPECTED), DiviAdapters::CLASSES, 'all eight adapters, in report order');
|
||||
}
|
||||
|
||||
public function testReadingAdaptersCarryNoWriteFeature(): void
|
||||
{
|
||||
$readingOnly = [DesignSystemReader::class, DiviRoles::class, DiviModules::class, DynamicContentMap::class];
|
||||
|
||||
foreach ($readingOnly as $class) {
|
||||
$manifest = DiviAdapters::manifests()[$class];
|
||||
foreach ($manifest->requirements() as $requirement) {
|
||||
foreach ($manifest->featuresOf($requirement) as $feature) {
|
||||
self::assertFalse($feature->isWrite(), $class . ': ' . $requirement->label());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testEveryMirrorServesAWriteFeature(): void
|
||||
{
|
||||
foreach (DiviAdapters::manifests() as $class => $manifest) {
|
||||
foreach ($manifest->mirrors as $mirror) {
|
||||
$writes = array_filter(
|
||||
$manifest->featuresOf($mirror),
|
||||
static fn (DiviFeature $feature): bool => $feature->isWrite()
|
||||
);
|
||||
self::assertNotSame([], $writes, $class . ': Nachbau ' . $mirror->id . ' dient keinem Schreib-Feature');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Release;
|
||||
|
||||
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class DiviFeatureTest extends TestCase
|
||||
{
|
||||
public function testTheElevenFeaturesAndTheirValues(): void
|
||||
{
|
||||
self::assertSame(
|
||||
[
|
||||
'PageRead' => 'page-read',
|
||||
'PageWrite' => 'page-write',
|
||||
'Catalog' => 'catalog',
|
||||
'DynamicSources' => 'dynamic-sources',
|
||||
'DesignRead' => 'design-read',
|
||||
'PresetWrite' => 'preset-write',
|
||||
'LibraryRead' => 'library-read',
|
||||
'LibraryWrite' => 'library-write',
|
||||
'Roles' => 'roles',
|
||||
'ThemeBuilderRead' => 'tb-read',
|
||||
'ThemeBuilderWrite' => 'tb-write',
|
||||
],
|
||||
array_column(array_map(
|
||||
static fn (DiviFeature $feature): array => [$feature->name, $feature->value],
|
||||
DiviFeature::cases()
|
||||
), 1, 0)
|
||||
);
|
||||
}
|
||||
|
||||
public function testOnlyTheFourWriteFeaturesWrite(): void
|
||||
{
|
||||
$writing = array_values(array_map(
|
||||
static fn (DiviFeature $feature): string => $feature->value,
|
||||
array_filter(DiviFeature::cases(), static fn (DiviFeature $feature): bool => $feature->isWrite())
|
||||
));
|
||||
|
||||
self::assertSame(['page-write', 'preset-write', 'library-write', 'tb-write'], $writing);
|
||||
}
|
||||
|
||||
public function testEveryFeatureHasAUniqueGermanLabel(): void
|
||||
{
|
||||
$labels = array_map(static fn (DiviFeature $feature): string => $feature->label(), DiviFeature::cases());
|
||||
|
||||
self::assertCount(count(DiviFeature::cases()), array_unique($labels));
|
||||
self::assertSame('Seiten schreiben', DiviFeature::PageWrite->label());
|
||||
self::assertSame('Theme Builder lesen', DiviFeature::ThemeBuilderRead->label());
|
||||
foreach ($labels as $label) {
|
||||
self::assertNotSame('', trim($label));
|
||||
}
|
||||
}
|
||||
|
||||
public function testValuesResolveBackToTheFeature(): void
|
||||
{
|
||||
self::assertSame(DiviFeature::ThemeBuilderWrite, DiviFeature::from('tb-write'));
|
||||
self::assertNull(DiviFeature::tryFrom('page'));
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ declare(strict_types=1);
|
||||
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Release;
|
||||
|
||||
use LIT\MCP\Integrations\Divi\Release\Call;
|
||||
use LIT\MCP\Integrations\Divi\Release\ConstantRequirement;
|
||||
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
||||
use LIT\MCP\Integrations\Divi\Release\Manifest;
|
||||
use LIT\MCP\Integrations\Divi\Release\Mirror;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@@ -53,4 +55,61 @@ final class ManifestTest extends TestCase
|
||||
);
|
||||
self::assertSame('Bibliothek', $manifest->area);
|
||||
}
|
||||
|
||||
public function testPlainConstantNamesBecomeRequirementsWithALabel(): void
|
||||
{
|
||||
$manifest = new Manifest(
|
||||
Manifest::CATALOG,
|
||||
constants: ['ET_BUILDER_PRODUCT_VERSION', new ConstantRequirement('ET_OTHER', [DiviFeature::Roles])]
|
||||
);
|
||||
|
||||
self::assertSame(
|
||||
['ET_BUILDER_PRODUCT_VERSION', 'ET_OTHER'],
|
||||
array_map(static fn (ConstantRequirement $constant): string => $constant->name, $manifest->constants)
|
||||
);
|
||||
self::assertSame('Konstante ET_OTHER', $manifest->constants[1]->label());
|
||||
self::assertSame([], $manifest->constants[0]->features());
|
||||
self::assertSame([DiviFeature::Roles], $manifest->constants[1]->features());
|
||||
self::assertSame(['ET_BUILDER_PRODUCT_VERSION', 'ET_OTHER'], $manifest->names());
|
||||
}
|
||||
|
||||
public function testRequirementsAreCallsConstantsAndMirrorsInThatOrder(): void
|
||||
{
|
||||
$call = new Call('et_pb_is_allowed', 1);
|
||||
$mirror = new Mirror('m', 'a.php', 'a', null, 'Terme');
|
||||
$manifest = new Manifest(Manifest::LIBRARY, calls: [$call], constants: ['ET_X'], mirrors: [$mirror]);
|
||||
|
||||
$requirements = $manifest->requirements();
|
||||
|
||||
self::assertCount(3, $requirements);
|
||||
self::assertSame($call, $requirements[0]);
|
||||
self::assertSame('Konstante ET_X', $requirements[1]->label());
|
||||
self::assertSame($mirror, $requirements[2]);
|
||||
}
|
||||
|
||||
public function testFeaturesOfPrefersTheOwnFeaturesOverTheManifestDefault(): void
|
||||
{
|
||||
$own = new Call('et_a', null, [DiviFeature::PageWrite, DiviFeature::ThemeBuilderWrite]);
|
||||
$inherited = new Call('et_b');
|
||||
$mirror = new Mirror('m', 'a.php', 'a', null, 'x', [DiviFeature::LibraryWrite]);
|
||||
$manifest = new Manifest(
|
||||
Manifest::PAGES,
|
||||
calls: [$own, $inherited],
|
||||
constants: ['ET_X'],
|
||||
mirrors: [$mirror],
|
||||
features: [DiviFeature::PageRead]
|
||||
);
|
||||
|
||||
self::assertSame([DiviFeature::PageWrite, DiviFeature::ThemeBuilderWrite], $manifest->featuresOf($own));
|
||||
self::assertSame([DiviFeature::PageRead], $manifest->featuresOf($inherited));
|
||||
self::assertSame([DiviFeature::PageRead], $manifest->featuresOf($manifest->constants[0]));
|
||||
self::assertSame([DiviFeature::LibraryWrite], $manifest->featuresOf($mirror));
|
||||
}
|
||||
|
||||
public function testWithoutAnyFeaturesAnEntryHasNone(): void
|
||||
{
|
||||
$call = new Call('et_a');
|
||||
|
||||
self::assertSame([], (new Manifest(Manifest::PAGES, calls: [$call]))->featuresOf($call));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace LIT\MCP\Tests\Unit\Integrations\Divi\Schema;
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DynamicContentMap;
|
||||
use LIT\MCP\Integrations\Divi\Release\Call;
|
||||
use LIT\MCP\Integrations\Divi\Release\ConstantRequirement;
|
||||
use LIT\MCP\Integrations\Divi\Release\DiviAdapters;
|
||||
use LIT\MCP\Integrations\Divi\Release\Manifest;
|
||||
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
||||
@@ -35,7 +36,10 @@ final class DiviModulesTest extends TestCase
|
||||
array_map(static fn (Call $call): string => $call->label(), $manifest->calls)
|
||||
);
|
||||
self::assertSame(['divi/global-layout'], $manifest->blockTypes);
|
||||
self::assertSame(['ET_BUILDER_PRODUCT_VERSION'], $manifest->constants);
|
||||
self::assertSame(
|
||||
['ET_BUILDER_PRODUCT_VERSION'],
|
||||
array_map(static fn (ConstantRequirement $constant): string => $constant->name, $manifest->constants)
|
||||
);
|
||||
}
|
||||
|
||||
public function testInternalPostTypesAreDivisOwn(): void
|
||||
|
||||
Reference in New Issue
Block a user