Files
WP-LIT-MCP/tests/Unit/Guides/InstructionsBuilderTest.php
T
2026-09-27 03:33:38 +02:00

165 lines
6.8 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\Guides;
use LIT\MCP\Abilities\Ability;
use LIT\MCP\Abilities\ExposurePolicy;
use LIT\MCP\Guides\InstructionsBuilder;
use LIT\MCP\Integrations\Integration;
use LIT\MCP\Integrations\IntegrationRegistry;
use LIT\MCP\Tests\Unit\TestCase;
use Mockery;
final class InstructionsBuilderTest extends TestCase
{
private function ability(string $name, bool $direct): Ability
{
$ability = Mockery::mock(Ability::class);
$ability->allows('name')->andReturn($name);
$ability->allows('isDirect')->andReturn($direct);
return $ability;
}
private function coreWith(Ability ...$abilities): Integration
{
$core = Mockery::mock(Integration::class);
$core->allows('id')->andReturn('core');
$core->allows('isAvailable')->andReturn(true);
$core->allows('abilities')->andReturn(array_values($abilities));
return $core;
}
public function testNamesActiveIntegrationsAndCoreRules(): void
{
$core = $this->coreWith($this->ability('lit/guide', true), $this->ability('lit/menu-list', false));
$text = (new InstructionsBuilder(new IntegrationRegistry($core)))->build();
self::assertStringContainsString('Aktive Integrationen: core', $text);
self::assertStringContainsString('lit-guide', $text);
self::assertStringContainsString('Status', $text);
self::assertLessThan(2000, strlen($text), 'Instructions must stay short – they are loaded in every conversation.');
}
public function testAddsTheDiviRuleOnlyWhenDiviIsActive(): void
{
$divi = Mockery::mock(Integration::class);
$divi->allows('id')->andReturn('divi');
$divi->allows('isAvailable')->andReturn(true);
$divi->allows('abilities')->andReturn([$this->ability('lit/divi-outline', true)]);
$core = $this->coreWith($this->ability('lit/guide', true));
$with = (new InstructionsBuilder(new IntegrationRegistry($core, $divi)))->build();
$without = (new InstructionsBuilder(new IntegrationRegistry($core)))->build();
self::assertStringContainsString('lit-divi-outline und lit-divi-design-system lesen', $with);
self::assertStringContainsString('tree_rev', $with);
self::assertStringNotContainsString('lit-divi-outline und', $without);
self::assertStringNotContainsString('tree_rev', $without);
self::assertLessThan(2000, strlen($with));
}
private function library(): Integration
{
$library = Mockery::mock(Integration::class);
$library->allows('id')->andReturn('divi-library');
$library->allows('isAvailable')->andReturn(true);
$insert = $this->ability('lit/library-insert', true);
$insert->allows('annotations')->andReturn(['readonly' => false]);
$library->allows('abilities')->andReturn([$insert]);
return $library;
}
public function testAddsTheLibraryRuleOnlyWhenTheLibraryGroupIsActive(): void
{
$core = $this->coreWith($this->ability('lit/guide', true));
$with = (new InstructionsBuilder(new IntegrationRegistry($core, $this->library())))->build();
$without = (new InstructionsBuilder(new IntegrationRegistry($core)))->build();
self::assertStringContainsString('Divi-Bibliothek: globale Module', $with);
self::assertStringContainsString('confirm: true', $with);
self::assertStringContainsString('topic "divi-library"', $with);
self::assertStringNotContainsString('Divi-Bibliothek:', $without);
self::assertLessThan(2000, strlen($with));
}
/** "nur lesen" or disabled: the library cannot be written, so the edit rule would only mislead. */
public function testLeavesOutTheLibraryRuleWhenTheGroupCannotWrite(): void
{
$core = $this->coreWith($this->ability('lit/guide', true));
$registry = new IntegrationRegistry($core, $this->library());
foreach ([['@readonly:divi-library' => true], ['@group:divi-library' => 'disabled']] as $settings) {
$policy = (new ExposurePolicy($settings))->withGroups($registry->groupMap());
$text = (new InstructionsBuilder($registry, null, $policy))->build();
self::assertStringNotContainsString('Divi-Bibliothek:', $text, (string) json_encode($settings));
}
}
public function testListsPostTypesWhenAProviderIsGiven(): void
{
$core = $this->coreWith($this->ability('lit/guide', true));
$text = (new InstructionsBuilder(new IntegrationRegistry($core), static fn (): array => ['page', 'post']))->build();
self::assertStringContainsString('Inhaltstypen: page, post', $text);
self::assertStringContainsString('lit-content-types', $text);
self::assertStringContainsString('confirm: true', $text);
}
public function testListsTheCurrentlyDirectToolsByToolNameAndNamesTheRestNeutrally(): void
{
$core = $this->coreWith(
$this->ability('lit/guide', true),
$this->ability('lit/menu-list', false)
);
$text = (new InstructionsBuilder(new IntegrationRegistry($core)))->build();
self::assertStringContainsString('Direkt aufrufbare Tools: lit-guide', $text);
self::assertStringContainsString('mcp-adapter-execute-ability', $text);
self::assertStringNotContainsString('lit-menu-list', $text);
}
public function testDirectToolListReflectsExposurePolicyOverrides(): void
{
$core = $this->coreWith(
$this->ability('lit/guide', true),
$this->ability('lit/menu-list', false)
);
$policy = new ExposurePolicy(['lit/menu-list' => 'direct']);
$text = (new InstructionsBuilder(new IntegrationRegistry($core), null, $policy))->build();
self::assertStringContainsString('lit-menu-list', $text);
}
public function testGroupDisabledAndReadonlyToolsAreNotListedAsDirect(): void
{
$write = $this->ability('lit/divi-update', true);
$write->allows('annotations')->andReturn(['readonly' => false]);
$read = $this->ability('lit/divi-outline', true);
$read->allows('annotations')->andReturn(['readonly' => true]);
$divi = Mockery::mock(Integration::class);
$divi->allows('id')->andReturn('divi');
$divi->allows('isAvailable')->andReturn(true);
$divi->allows('abilities')->andReturn([$write, $read]);
$core = $this->coreWith($this->ability('lit/guide', true), $this->ability('lit/menu-list', true));
$registry = new IntegrationRegistry($core, $divi);
$policy = (new ExposurePolicy(['@group:core' => 'disabled', '@readonly:divi' => true]))
->withGroups($registry->groupMap());
$text = (new InstructionsBuilder($registry, null, $policy))->build();
self::assertStringContainsString('Direkt aufrufbare Tools: lit-guide, lit-divi-outline.', $text);
}
}