feat: media usage finder and media-get tool
Usage search distinguishes certain (ID referenced) and possible (file URL only) usages, hides titles the user cannot read, and keeps queries bounded. MediaGuard checks per-attachment capabilities and refuses trashed media unless the caller opts in. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Tests\Unit\Integrations\Media;
|
||||
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Integrations\Media\MediaPresenter;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use stdClass;
|
||||
use WP_Post;
|
||||
|
||||
final class MediaPresenterTest extends TestCase
|
||||
{
|
||||
private function attachment(): WP_Post
|
||||
{
|
||||
return new WP_Post([
|
||||
'ID' => 33,
|
||||
'post_type' => 'attachment',
|
||||
'post_title' => 'Foto',
|
||||
'post_mime_type' => 'image/jpeg',
|
||||
'post_excerpt' => 'Bildunterschrift',
|
||||
'post_content' => 'Beschreibung',
|
||||
'post_parent' => 5,
|
||||
]);
|
||||
}
|
||||
|
||||
private function stubCommon(array $meta): void
|
||||
{
|
||||
Functions\when('wp_get_attachment_metadata')->justReturn($meta);
|
||||
Functions\when('get_attached_file')->justReturn('/var/www/html/wp-content/uploads/2026/09/foto.jpg');
|
||||
Functions\when('wp_basename')->alias('basename');
|
||||
Functions\when('wp_get_attachment_url')->justReturn('https://kunde.de/wp-content/uploads/2026/09/foto.jpg');
|
||||
Functions\when('get_post_meta')->justReturn('Porträt');
|
||||
Functions\when('get_edit_post_link')->justReturn('https://kunde.de/wp-admin/post.php?post=33&action=edit');
|
||||
}
|
||||
|
||||
public function testSummaryHasFileDataAndAlt(): void
|
||||
{
|
||||
$this->stubCommon(['width' => 1600, 'height' => 900, 'filesize' => 123456]);
|
||||
|
||||
$summary = (new MediaPresenter())->summary($this->attachment());
|
||||
|
||||
self::assertSame('foto.jpg', $summary['filename']);
|
||||
self::assertSame('Porträt', $summary['alt']);
|
||||
self::assertSame(1600, $summary['width']);
|
||||
self::assertSame(123456, $summary['filesize']);
|
||||
}
|
||||
|
||||
public function testFullListsSizesAndUsagesAndCopesWithMissingMetadata(): void
|
||||
{
|
||||
$this->stubCommon(['sizes' => ['medium' => ['width' => 300, 'height' => 169]]]);
|
||||
Functions\when('wp_get_attachment_image_src')->justReturn(['https://kunde.de/foto-300x169.jpg', 300, 169, true]);
|
||||
$usages = [['post_id' => 5, 'title' => 'Team', 'post_type' => 'page', 'where' => 'featured', 'certainty' => 'sicher']];
|
||||
|
||||
$full = (new MediaPresenter())->full($this->attachment(), $usages);
|
||||
|
||||
self::assertSame(['medium' => ['url' => 'https://kunde.de/foto-300x169.jpg', 'width' => 300, 'height' => 169]], $full['sizes']);
|
||||
self::assertSame($usages, $full['usages']);
|
||||
self::assertSame('Bildunterschrift', $full['caption']);
|
||||
self::assertSame(5, $full['parent']);
|
||||
self::assertSame('https://kunde.de/wp-admin/post.php?post=33&action=edit', $full['edit_url']);
|
||||
self::assertNull($full['width']);
|
||||
|
||||
Functions\when('wp_get_attachment_metadata')->justReturn(false);
|
||||
self::assertInstanceOf(stdClass::class, (new MediaPresenter())->full($this->attachment(), [])['sizes']);
|
||||
}
|
||||
|
||||
public function testFullSchemaRequiresSizesAndUsagesAndDescribesUsages(): void
|
||||
{
|
||||
$schema = MediaPresenter::fullSchema();
|
||||
|
||||
self::assertContains('sizes', $schema['required']);
|
||||
self::assertContains('usages', $schema['required']);
|
||||
self::assertSame(['sicher', 'möglicherweise'], $schema['properties']['usages']['items']['properties']['certainty']['enum']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user