refactor(compat): Freigabe-Bausteine generisch
ReleaseStore, CheckReportStore, CheckReport, CheckStep und CompatibilityCheck liegen im Kern und arbeiten je Profil (Optionen lit_mcp_<id>_releases|_check_report; Divi behält Namen und Schlüssel divi_version). Divi hängt Katalog-, Format- und Schreibtest über Profile::extraSteps an. Ein roter Prüfbericht für den aktuellen Stand sperrt LockOnFailure-Profile bis zur nächsten grünen Prüfung; Sperrgründe nennen nur Schritt-Labels, Ausnahmen gehen ins Error-Log. Profile bekommt testedVersions, stateKey, extraSteps, manifestCheck und reportVersionKey und wird mit benannten Argumenten gebaut. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c85131603b
commit
7d6a97a54e
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Tests\Unit\Compatibility;
|
||||
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Compatibility\CheckReport;
|
||||
use LIT\MCP\Compatibility\CheckReportStore;
|
||||
use LIT\MCP\Compatibility\CheckStep;
|
||||
use LIT\MCP\Compatibility\Compatibility;
|
||||
use LIT\MCP\Compatibility\Profile;
|
||||
use LIT\MCP\Compatibility\ReleaseStore;
|
||||
use LIT\MCP\Compatibility\Tier;
|
||||
use LIT\MCP\Tests\Support\FakeCapability;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
|
||||
final class CheckReportTest extends TestCase
|
||||
{
|
||||
/** @var array<string, mixed> */
|
||||
private array $options = [];
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->options = [];
|
||||
Functions\when('get_option')->alias(
|
||||
fn (string $name, mixed $default = false): mixed => $this->options[$name] ?? $default
|
||||
);
|
||||
Functions\when('update_option')->alias(function (string $name, mixed $value, mixed $autoload = null): bool {
|
||||
$this->options[$name] = $value;
|
||||
self::assertFalse($autoload, 'the report is read in the admin only – no autoload');
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/** @param list<CheckStep> $steps */
|
||||
private static function report(array $steps): CheckReport
|
||||
{
|
||||
return new CheckReport('r1', '2026-10-01T08:00:00+00:00', 1, '5.3.0', '0.6.0', 'key', $steps);
|
||||
}
|
||||
|
||||
/** @return list<CheckStep> */
|
||||
private static function green(): array
|
||||
{
|
||||
return array_map(
|
||||
static fn (string $key): CheckStep => new CheckStep($key, []),
|
||||
[CheckStep::MANIFEST, CheckStep::MIRRORS, 'catalog']
|
||||
);
|
||||
}
|
||||
|
||||
/** What the Divi report looked like before the generic version: no label per step, key divi_version. */
|
||||
private static function oldDiviReport(): array
|
||||
{
|
||||
return [
|
||||
'id' => 'r1',
|
||||
'created_at' => '2026-10-01T08:00:00+00:00',
|
||||
'user_id' => 1,
|
||||
'divi_version' => '5.3.0',
|
||||
'plugin_version' => '0.6.0',
|
||||
'state_key' => 'key',
|
||||
'steps' => [
|
||||
['key' => 'manifest', 'problems' => [], 'skipped' => false],
|
||||
['key' => 'mirrors', 'problems' => ['Theme Builder: Nachbau von x() – y'], 'skipped' => false],
|
||||
['key' => 'write', 'problems' => [], 'skipped' => true],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function testGreenOnlyWithEveryStepGreenAndNoneSkipped(): void
|
||||
{
|
||||
self::assertTrue(self::report(self::green())->green());
|
||||
self::assertFalse(self::report([])->green());
|
||||
|
||||
$red = self::green();
|
||||
$red[2] = new CheckStep('catalog', ['divi/text: unbekanntes Modul']);
|
||||
self::assertFalse(self::report($red)->green());
|
||||
|
||||
$skipped = self::green();
|
||||
$skipped[2] = new CheckStep('catalog', [], true);
|
||||
self::assertFalse(self::report($skipped)->green());
|
||||
}
|
||||
|
||||
public function testFreshOnlyForTheSameVersionsAndStateKey(): void
|
||||
{
|
||||
$report = self::report(self::green());
|
||||
|
||||
self::assertTrue($report->freshFor('5.3.0', '0.6.0', 'key'));
|
||||
self::assertFalse($report->freshFor('5.3.1', '0.6.0', 'key'), 'plugin under test updated');
|
||||
self::assertFalse($report->freshFor('5.3.0', '0.7.0', 'key'), 'this plugin updated');
|
||||
self::assertFalse($report->freshFor('5.3.0', '0.6.0', 'other'), 'a source file changed');
|
||||
}
|
||||
|
||||
public function testRoundTripsThroughAnArrayWithTheLabel(): void
|
||||
{
|
||||
$steps = self::green();
|
||||
$steps[1] = new CheckStep(CheckStep::MIRRORS, ['x'], false, 'Fingerabdrücke');
|
||||
$report = self::report($steps);
|
||||
|
||||
self::assertEquals($report, CheckReport::fromArray($report->toArray()));
|
||||
self::assertSame('Fingerabdrücke', $report->step(CheckStep::MIRRORS)?->label());
|
||||
self::assertSame('Fingerabdrücke', $report->toArray()['steps'][1]['label']);
|
||||
self::assertNull(CheckReport::fromArray('broken'));
|
||||
self::assertNull(CheckReport::fromArray(['id' => 'r1']));
|
||||
}
|
||||
|
||||
public function testAStepWithoutLabelShowsItsKeyAndIsWrittenWithoutOne(): void
|
||||
{
|
||||
$step = new CheckStep('catalog', []);
|
||||
|
||||
self::assertSame('catalog', $step->label());
|
||||
self::assertArrayNotHasKey('label', $step->toArray());
|
||||
}
|
||||
|
||||
public function testTheGenericStepsHaveOneLabelSourceWithTheProfileName(): void
|
||||
{
|
||||
self::assertSame('Pods-Funktionen, Klassen und Registrierungen', CheckStep::genericLabel(CheckStep::MANIFEST, 'Pods'));
|
||||
self::assertSame('Fingerabdrücke nachgebauter Pods-Funktionen', CheckStep::genericLabel(CheckStep::MIRRORS, 'Pods'));
|
||||
self::assertNull(CheckStep::genericLabel('catalog', 'Pods'));
|
||||
}
|
||||
|
||||
public function testAReportWithoutStepsIsNotGreen(): void
|
||||
{
|
||||
self::assertFalse(self::report([])->green());
|
||||
}
|
||||
|
||||
public function testAnOldDiviReportIsReadAndWrittenUnchanged(): void
|
||||
{
|
||||
$old = self::oldDiviReport();
|
||||
|
||||
$report = CheckReport::fromArray($old, 'divi_version');
|
||||
|
||||
self::assertSame('5.3.0', $report?->version);
|
||||
self::assertSame('manifest', $report?->steps[0]->label(), 'no stored label: the raw key');
|
||||
self::assertSame($old, $report?->toArray('divi_version'));
|
||||
self::assertNull(CheckReport::fromArray($old), 'the default key is "version"');
|
||||
}
|
||||
|
||||
public function testTheStoreKeepsTheDiviOptionAndFormat(): void
|
||||
{
|
||||
$this->options['lit_mcp_divi_check_report'] = self::oldDiviReport();
|
||||
$store = new CheckReportStore('divi', 'divi_version');
|
||||
|
||||
$report = $store->latest();
|
||||
self::assertSame('r1', $report?->id);
|
||||
|
||||
$store->save($report);
|
||||
self::assertSame(self::oldDiviReport(), $this->options['lit_mcp_divi_check_report']);
|
||||
}
|
||||
|
||||
public function testTheStoresOfAProfileUseItsIdAndVersionKey(): void
|
||||
{
|
||||
$profile = new Profile(
|
||||
id: 'divi',
|
||||
label: 'Divi',
|
||||
tier: Tier::ReportOnly,
|
||||
capabilities: [FakeCapability::Read],
|
||||
reportVersionKey: 'divi_version'
|
||||
);
|
||||
$this->options['lit_mcp_divi_check_report'] = self::oldDiviReport();
|
||||
$this->options['lit_mcp_divi_releases'] = [[
|
||||
'divi_version' => '5.2.2', 'plugin_version' => '0.6.0', 'user_id' => 3,
|
||||
'released_at' => '2026-10-01T08:00:00+00:00', 'report_id' => 'r',
|
||||
]];
|
||||
|
||||
self::assertSame('r1', CheckReportStore::forProfile($profile)->latest()?->id);
|
||||
self::assertSame('r', ReleaseStore::forProfile($profile)->find('5.2.2', '0.6.0')['report_id'] ?? null);
|
||||
}
|
||||
|
||||
public function testStoredReportReadsTheDiviFormatForAProfileWithItsKey(): void
|
||||
{
|
||||
$profile = new Profile(
|
||||
id: 'divi',
|
||||
label: 'Divi',
|
||||
tier: Tier::ReportOnly,
|
||||
capabilities: [FakeCapability::Read],
|
||||
reportVersionKey: 'divi_version'
|
||||
);
|
||||
$this->options['lit_mcp_divi_check_report'] = self::oldDiviReport();
|
||||
|
||||
self::assertSame('5.3.0', Compatibility::storedReport($profile)?->version);
|
||||
}
|
||||
|
||||
public function testTheStoreUsesAnOptionAndVersionKeyPerProfile(): void
|
||||
{
|
||||
$store = new CheckReportStore('pods');
|
||||
self::assertNull($store->latest());
|
||||
|
||||
$store->save(self::report(self::green()));
|
||||
|
||||
self::assertSame(['lit_mcp_pods_check_report'], array_keys($this->options));
|
||||
self::assertSame('5.3.0', $this->options['lit_mcp_pods_check_report']['version']);
|
||||
self::assertSame('5.3.0', $store->latest()?->version);
|
||||
self::assertNull((new CheckReportStore('divi', 'divi_version'))->latest());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user