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>
65 lines
2.4 KiB
PHP
65 lines
2.4 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace LIT\MCP\Tests\Unit\Compatibility;
|
||
|
||
use LIT\MCP\Abilities\ToolRefusal;
|
||
use LIT\MCP\Compatibility\CapabilityLocked;
|
||
use LIT\MCP\Compatibility\FeatureStatus;
|
||
use LIT\MCP\Compatibility\Profile;
|
||
use LIT\MCP\Compatibility\ReleaseState;
|
||
use LIT\MCP\Compatibility\Tier;
|
||
use LIT\MCP\Tests\Support\FakeCapability;
|
||
use LIT\MCP\Tests\Unit\TestCase;
|
||
use LogicException;
|
||
|
||
final class CapabilityLockedTest extends TestCase
|
||
{
|
||
public function testTheErrorNamesPluginCapabilitiesAndProblems(): void
|
||
{
|
||
$profile = new Profile(id: 'fake', label: 'Fake Plugin', tier: Tier::LockOnFailure, capabilities: [FakeCapability::Write]);
|
||
$locked = CapabilityLocked::of(
|
||
[new FeatureStatus(FakeCapability::Write, ReleaseState::Incompatible, ['Fake: x() fehlt'])],
|
||
[$profile]
|
||
);
|
||
|
||
self::assertInstanceOf(ToolRefusal::class, $locked);
|
||
self::assertSame('Fake Plugin locked – fake-write refused', $locked->getMessage());
|
||
$error = $locked->toError();
|
||
$payload = self::assertToolError($error, 'compat_incompatible');
|
||
self::assertSame(423, $error->get_error_data()['status']);
|
||
self::assertStringContainsString('Fake Plugin', $payload['message']);
|
||
self::assertStringContainsString('Fake fake-write', $payload['message']);
|
||
self::assertNotSame('', $payload['hint']);
|
||
self::assertSame(['fake-write'], array_column($payload['features'], 'id'));
|
||
self::assertSame(['Fake: x() fehlt'], $payload['problems']);
|
||
}
|
||
|
||
public function testALockWithoutLockedCapabilitiesIsAProgrammingError(): void
|
||
{
|
||
$this->expectException(LogicException::class);
|
||
|
||
CapabilityLocked::of([], []);
|
||
}
|
||
|
||
public function testUnknownIdsLockTheCall(): void
|
||
{
|
||
$locked = CapabilityLocked::unknown(['fake-x', 'fake-y']);
|
||
|
||
$error = $locked->toError();
|
||
$payload = self::assertToolError($error, 'compat_incompatible');
|
||
self::assertSame(423, $error->get_error_data()['status']);
|
||
self::assertSame(['fake-x', 'fake-y'], $payload['unknown']);
|
||
self::assertStringContainsString('fake-x, fake-y', $payload['message']);
|
||
self::assertSame(['fake-x', 'fake-y'], $locked->unknown);
|
||
}
|
||
|
||
public function testUnknownNeedsAtLeastOneId(): void
|
||
{
|
||
$this->expectException(LogicException::class);
|
||
|
||
CapabilityLocked::unknown([]);
|
||
}
|
||
}
|