* fix: allow URIs without double slash in Resource and ResourceTemplate (RFC 3986) The URI regex required "://" after the scheme, rejecting valid URIs like urn:isbn:123, mailto:user@example.com, config:key, and data: URIs. RFC 3986 only requires ":" after the scheme; the "//" is part of the authority component which is optional. Changed both Resource.URI_PATTERN and ResourceTemplate.URI_TEMPLATE_PATTERN to require ":" instead of "://". Adds data-provider tests for URIs without double slash in both classes. Fixes #293 * Reword unit tests --------- Co-authored-by: Christopher Hertel <mail@christopher-hertel.de>
109 lines
3.2 KiB
PHP
109 lines
3.2 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of the official PHP MCP SDK.
|
|
*
|
|
* A collaboration between Symfony and the PHP Foundation.
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Mcp\Tests\Unit\Schema;
|
|
|
|
use Mcp\Exception\InvalidArgumentException;
|
|
use Mcp\Schema\Resource;
|
|
use PHPUnit\Framework\Attributes\DataProvider;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class ResourceTest extends TestCase
|
|
{
|
|
private const VALID_URI = 'https://example.com/list-books';
|
|
|
|
public function testConstructorValid(): void
|
|
{
|
|
$uri = self::VALID_URI;
|
|
|
|
$resource = new Resource(
|
|
uri: $uri,
|
|
name: 'list-books',
|
|
);
|
|
|
|
$this->assertInstanceOf(Resource::class, $resource);
|
|
$this->assertSame($uri, $resource->uri);
|
|
}
|
|
|
|
public function testConstructorInvalid(): void
|
|
{
|
|
$uri = '/list-books';
|
|
|
|
$this->expectException(InvalidArgumentException::class);
|
|
$this->expectExceptionMessage('Invalid resource URI: "/list-books" must be a valid URI with a scheme and optional path.');
|
|
|
|
$resource = new Resource(
|
|
uri: $uri,
|
|
name: 'list-books',
|
|
);
|
|
}
|
|
|
|
#[DataProvider('provideValidUris')]
|
|
public function testConstructorAcceptsUris(string $uri): void
|
|
{
|
|
$resource = new Resource(
|
|
uri: $uri,
|
|
name: 'test-resource',
|
|
);
|
|
|
|
$this->assertInstanceOf(Resource::class, $resource);
|
|
$this->assertSame($uri, $resource->uri);
|
|
}
|
|
|
|
public static function provideValidUris(): iterable
|
|
{
|
|
yield 'urn' => ['urn:isbn:0451450523'];
|
|
yield 'mailto' => ['mailto:user@example.com'];
|
|
yield 'data' => ['data:text/plain;base64,SGVsbG8='];
|
|
yield 'custom scheme without slashes' => ['config:myapp/settings'];
|
|
yield 'custom scheme with slashes' => ['config://myapp/settings'];
|
|
}
|
|
|
|
public function testFromArrayValid(): void
|
|
{
|
|
$resource = Resource::fromArray([
|
|
'uri' => self::VALID_URI,
|
|
'name' => 'list-books',
|
|
]);
|
|
|
|
$this->assertInstanceOf(Resource::class, $resource);
|
|
$this->assertSame(self::VALID_URI, $resource->uri);
|
|
$this->assertSame('list-books', $resource->name);
|
|
$this->assertNull($resource->description);
|
|
$this->assertNull($resource->meta);
|
|
}
|
|
|
|
#[DataProvider('provideInvalidResources')]
|
|
public function testFromArrayInvalid(array $input, string $expectedExceptionMessage): void
|
|
{
|
|
$this->expectException(InvalidArgumentException::class);
|
|
$this->expectExceptionMessage($expectedExceptionMessage);
|
|
|
|
Resource::fromArray($input);
|
|
}
|
|
|
|
public static function provideInvalidResources(): iterable
|
|
{
|
|
yield 'missing uri' => [[], 'Invalid or missing "uri" in Resource data.'];
|
|
yield 'missing name' => [
|
|
['uri' => self::VALID_URI],
|
|
'Invalid or missing "name" in Resource data.',
|
|
];
|
|
yield 'meta' => [
|
|
[
|
|
'uri' => self::VALID_URI,
|
|
'name' => 'list-books',
|
|
'_meta' => 'foo',
|
|
],
|
|
'Invalid "_meta" in Resource data.',
|
|
];
|
|
}
|
|
}
|