Add elicitation support for server-to-client user input requests (#228)
- Add ElicitAction enum (accept/decline/cancel) - Add schema definitions for elicitation fields (string, number, boolean, enum) - Add ElicitationSchema wrapper for requestedSchema - Add ElicitRequest and ElicitResult for elicitation/create method - Update ClientCapabilities to support elicitation capability - Add elicit() method to ClientGateway - Store client capabilities in session during initialization - Add comprehensive unit tests - Add elicitation example server with book_restaurant, confirm_action, and collect_feedback tools
This commit is contained in:
parent
aafac3ddf5
commit
02e86377e4
10 changed files with 2582 additions and 5 deletions
110
tests/Unit/Schema/Elicitation/BooleanSchemaDefinitionTest.php
Normal file
110
tests/Unit/Schema/Elicitation/BooleanSchemaDefinitionTest.php
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Elicitation;
|
||||
|
||||
use Mcp\Exception\InvalidArgumentException;
|
||||
use Mcp\Schema\Elicitation\BooleanSchemaDefinition;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class BooleanSchemaDefinitionTest extends TestCase
|
||||
{
|
||||
public function testConstructorWithMinimalParams(): void
|
||||
{
|
||||
$schema = new BooleanSchemaDefinition('Confirm');
|
||||
|
||||
$this->assertSame('Confirm', $schema->title);
|
||||
$this->assertNull($schema->description);
|
||||
$this->assertNull($schema->default);
|
||||
}
|
||||
|
||||
public function testConstructorWithAllParams(): void
|
||||
{
|
||||
$schema = new BooleanSchemaDefinition(
|
||||
title: 'Confirmation',
|
||||
description: 'Do you confirm this action?',
|
||||
default: false,
|
||||
);
|
||||
|
||||
$this->assertSame('Confirmation', $schema->title);
|
||||
$this->assertSame('Do you confirm this action?', $schema->description);
|
||||
$this->assertFalse($schema->default);
|
||||
}
|
||||
|
||||
public function testConstructorWithTrueDefault(): void
|
||||
{
|
||||
$schema = new BooleanSchemaDefinition(
|
||||
title: 'Subscribe',
|
||||
default: true,
|
||||
);
|
||||
|
||||
$this->assertTrue($schema->default);
|
||||
}
|
||||
|
||||
public function testFromArrayWithMinimalParams(): void
|
||||
{
|
||||
$schema = BooleanSchemaDefinition::fromArray(['title' => 'Confirm']);
|
||||
|
||||
$this->assertSame('Confirm', $schema->title);
|
||||
$this->assertNull($schema->description);
|
||||
$this->assertNull($schema->default);
|
||||
}
|
||||
|
||||
public function testFromArrayWithAllParams(): void
|
||||
{
|
||||
$schema = BooleanSchemaDefinition::fromArray([
|
||||
'title' => 'Confirmation',
|
||||
'description' => 'Do you confirm this action?',
|
||||
'default' => true,
|
||||
]);
|
||||
|
||||
$this->assertSame('Confirmation', $schema->title);
|
||||
$this->assertSame('Do you confirm this action?', $schema->description);
|
||||
$this->assertTrue($schema->default);
|
||||
}
|
||||
|
||||
public function testFromArrayWithMissingTitle(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Missing or invalid "title"');
|
||||
|
||||
/* @phpstan-ignore argument.type */
|
||||
BooleanSchemaDefinition::fromArray([]);
|
||||
}
|
||||
|
||||
public function testJsonSerializeWithMinimalParams(): void
|
||||
{
|
||||
$schema = new BooleanSchemaDefinition('Confirm');
|
||||
|
||||
$this->assertSame([
|
||||
'type' => 'boolean',
|
||||
'title' => 'Confirm',
|
||||
], $schema->jsonSerialize());
|
||||
}
|
||||
|
||||
public function testJsonSerializeWithAllParams(): void
|
||||
{
|
||||
$schema = new BooleanSchemaDefinition(
|
||||
title: 'Confirmation',
|
||||
description: 'Do you confirm this action?',
|
||||
default: false,
|
||||
);
|
||||
|
||||
$this->assertSame([
|
||||
'type' => 'boolean',
|
||||
'title' => 'Confirmation',
|
||||
'description' => 'Do you confirm this action?',
|
||||
'default' => false,
|
||||
], $schema->jsonSerialize());
|
||||
}
|
||||
}
|
||||
221
tests/Unit/Schema/Elicitation/ElicitationSchemaTest.php
Normal file
221
tests/Unit/Schema/Elicitation/ElicitationSchemaTest.php
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Elicitation;
|
||||
|
||||
use Mcp\Exception\InvalidArgumentException;
|
||||
use Mcp\Schema\Elicitation\BooleanSchemaDefinition;
|
||||
use Mcp\Schema\Elicitation\ElicitationSchema;
|
||||
use Mcp\Schema\Elicitation\EnumSchemaDefinition;
|
||||
use Mcp\Schema\Elicitation\NumberSchemaDefinition;
|
||||
use Mcp\Schema\Elicitation\StringSchemaDefinition;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class ElicitationSchemaTest extends TestCase
|
||||
{
|
||||
public function testConstructorWithMinimalParams(): void
|
||||
{
|
||||
$properties = [
|
||||
'name' => new StringSchemaDefinition('Name'),
|
||||
];
|
||||
|
||||
$schema = new ElicitationSchema($properties);
|
||||
|
||||
$this->assertCount(1, $schema->properties);
|
||||
$this->assertSame([], $schema->required);
|
||||
}
|
||||
|
||||
public function testConstructorWithRequiredFields(): void
|
||||
{
|
||||
$properties = [
|
||||
'name' => new StringSchemaDefinition('Name'),
|
||||
'email' => new StringSchemaDefinition('Email'),
|
||||
];
|
||||
|
||||
$schema = new ElicitationSchema($properties, ['name']);
|
||||
|
||||
$this->assertCount(2, $schema->properties);
|
||||
$this->assertSame(['name'], $schema->required);
|
||||
}
|
||||
|
||||
public function testConstructorWithMultipleTypes(): void
|
||||
{
|
||||
$properties = [
|
||||
'name' => new StringSchemaDefinition('Name'),
|
||||
'age' => new NumberSchemaDefinition('Age', integerOnly: true),
|
||||
'subscribe' => new BooleanSchemaDefinition('Subscribe'),
|
||||
'rating' => new EnumSchemaDefinition('Rating', ['1', '2', '3', '4', '5']),
|
||||
];
|
||||
|
||||
$schema = new ElicitationSchema($properties, ['name', 'age']);
|
||||
|
||||
$this->assertCount(4, $schema->properties);
|
||||
$this->assertInstanceOf(StringSchemaDefinition::class, $schema->properties['name']);
|
||||
$this->assertInstanceOf(NumberSchemaDefinition::class, $schema->properties['age']);
|
||||
$this->assertInstanceOf(BooleanSchemaDefinition::class, $schema->properties['subscribe']);
|
||||
$this->assertInstanceOf(EnumSchemaDefinition::class, $schema->properties['rating']);
|
||||
}
|
||||
|
||||
public function testConstructorWithEmptyProperties(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('properties array must not be empty');
|
||||
|
||||
new ElicitationSchema([]);
|
||||
}
|
||||
|
||||
public function testConstructorWithInvalidRequired(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Required property "unknown" is not defined in properties');
|
||||
|
||||
new ElicitationSchema(
|
||||
['name' => new StringSchemaDefinition('Name')],
|
||||
['unknown'],
|
||||
);
|
||||
}
|
||||
|
||||
public function testFromArrayWithMinimalParams(): void
|
||||
{
|
||||
$schema = ElicitationSchema::fromArray([
|
||||
'properties' => [
|
||||
'name' => ['type' => 'string', 'title' => 'Name'],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertCount(1, $schema->properties);
|
||||
$this->assertInstanceOf(StringSchemaDefinition::class, $schema->properties['name']);
|
||||
}
|
||||
|
||||
public function testFromArrayWithExplicitObjectType(): void
|
||||
{
|
||||
$schema = ElicitationSchema::fromArray([
|
||||
'type' => 'object',
|
||||
'properties' => [
|
||||
'name' => ['type' => 'string', 'title' => 'Name'],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertCount(1, $schema->properties);
|
||||
}
|
||||
|
||||
public function testFromArrayWithInvalidType(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('ElicitationSchema type must be "object"');
|
||||
|
||||
ElicitationSchema::fromArray([
|
||||
'type' => 'array',
|
||||
'properties' => [
|
||||
'name' => ['type' => 'string', 'title' => 'Name'],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function testFromArrayWithMissingProperties(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Missing or invalid "properties"');
|
||||
|
||||
/* @phpstan-ignore argument.type */
|
||||
ElicitationSchema::fromArray([]);
|
||||
}
|
||||
|
||||
public function testFromArrayWithRequiredFields(): void
|
||||
{
|
||||
$schema = ElicitationSchema::fromArray([
|
||||
'properties' => [
|
||||
'name' => ['type' => 'string', 'title' => 'Name'],
|
||||
'email' => ['type' => 'string', 'title' => 'Email', 'format' => 'email'],
|
||||
],
|
||||
'required' => ['name'],
|
||||
]);
|
||||
|
||||
$this->assertSame(['name'], $schema->required);
|
||||
}
|
||||
|
||||
public function testFromArrayWithMultipleTypes(): void
|
||||
{
|
||||
$schema = ElicitationSchema::fromArray([
|
||||
'properties' => [
|
||||
'name' => ['type' => 'string', 'title' => 'Name'],
|
||||
'age' => ['type' => 'integer', 'title' => 'Age', 'minimum' => 0],
|
||||
'confirm' => ['type' => 'boolean', 'title' => 'Confirm'],
|
||||
'rating' => ['type' => 'string', 'title' => 'Rating', 'enum' => ['1', '2', '3']],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(StringSchemaDefinition::class, $schema->properties['name']);
|
||||
$this->assertInstanceOf(NumberSchemaDefinition::class, $schema->properties['age']);
|
||||
$this->assertInstanceOf(BooleanSchemaDefinition::class, $schema->properties['confirm']);
|
||||
$this->assertInstanceOf(EnumSchemaDefinition::class, $schema->properties['rating']);
|
||||
}
|
||||
|
||||
public function testJsonSerializeWithMinimalParams(): void
|
||||
{
|
||||
$schema = new ElicitationSchema([
|
||||
'name' => new StringSchemaDefinition('Name'),
|
||||
]);
|
||||
|
||||
$result = $schema->jsonSerialize();
|
||||
|
||||
$this->assertSame('object', $result['type']);
|
||||
$this->assertArrayHasKey('name', $result['properties']);
|
||||
$this->assertSame('string', $result['properties']['name']['type']);
|
||||
$this->assertArrayNotHasKey('required', $result);
|
||||
}
|
||||
|
||||
public function testJsonSerializeWithRequiredFields(): void
|
||||
{
|
||||
$schema = new ElicitationSchema(
|
||||
[
|
||||
'name' => new StringSchemaDefinition('Name'),
|
||||
'email' => new StringSchemaDefinition('Email'),
|
||||
],
|
||||
['name'],
|
||||
);
|
||||
|
||||
$result = $schema->jsonSerialize();
|
||||
|
||||
$this->assertSame(['name'], $result['required']);
|
||||
}
|
||||
|
||||
public function testJsonSerializeWithFullSchema(): void
|
||||
{
|
||||
$schema = new ElicitationSchema(
|
||||
[
|
||||
'name' => new StringSchemaDefinition('Full Name', description: 'Your full name'),
|
||||
'age' => new NumberSchemaDefinition('Age', integerOnly: true, minimum: 0, maximum: 150),
|
||||
'subscribe' => new BooleanSchemaDefinition('Subscribe', default: false),
|
||||
],
|
||||
['name', 'age'],
|
||||
);
|
||||
|
||||
$result = $schema->jsonSerialize();
|
||||
|
||||
$this->assertSame('object', $result['type']);
|
||||
$this->assertCount(3, $result['properties']);
|
||||
$this->assertSame(['name', 'age'], $result['required']);
|
||||
|
||||
$this->assertSame('string', $result['properties']['name']['type']);
|
||||
$this->assertSame('Full Name', $result['properties']['name']['title']);
|
||||
$this->assertSame('Your full name', $result['properties']['name']['description']);
|
||||
|
||||
$this->assertSame('integer', $result['properties']['age']['type']);
|
||||
$this->assertSame(0, $result['properties']['age']['minimum']);
|
||||
$this->assertSame(150, $result['properties']['age']['maximum']);
|
||||
|
||||
$this->assertSame('boolean', $result['properties']['subscribe']['type']);
|
||||
$this->assertFalse($result['properties']['subscribe']['default']);
|
||||
}
|
||||
}
|
||||
167
tests/Unit/Schema/Elicitation/EnumSchemaDefinitionTest.php
Normal file
167
tests/Unit/Schema/Elicitation/EnumSchemaDefinitionTest.php
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Elicitation;
|
||||
|
||||
use Mcp\Exception\InvalidArgumentException;
|
||||
use Mcp\Schema\Elicitation\EnumSchemaDefinition;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class EnumSchemaDefinitionTest extends TestCase
|
||||
{
|
||||
public function testConstructorWithMinimalParams(): void
|
||||
{
|
||||
$schema = new EnumSchemaDefinition('Rating', ['1', '2', '3', '4', '5']);
|
||||
|
||||
$this->assertSame('Rating', $schema->title);
|
||||
$this->assertSame(['1', '2', '3', '4', '5'], $schema->enum);
|
||||
$this->assertNull($schema->description);
|
||||
$this->assertNull($schema->default);
|
||||
$this->assertNull($schema->enumNames);
|
||||
}
|
||||
|
||||
public function testConstructorWithAllParams(): void
|
||||
{
|
||||
$schema = new EnumSchemaDefinition(
|
||||
title: 'Satisfaction',
|
||||
enum: ['poor', 'fair', 'good', 'excellent'],
|
||||
description: 'Rate your satisfaction',
|
||||
default: 'good',
|
||||
enumNames: ['Poor', 'Fair', 'Good', 'Excellent'],
|
||||
);
|
||||
|
||||
$this->assertSame('Satisfaction', $schema->title);
|
||||
$this->assertSame(['poor', 'fair', 'good', 'excellent'], $schema->enum);
|
||||
$this->assertSame('Rate your satisfaction', $schema->description);
|
||||
$this->assertSame('good', $schema->default);
|
||||
$this->assertSame(['Poor', 'Fair', 'Good', 'Excellent'], $schema->enumNames);
|
||||
}
|
||||
|
||||
public function testConstructorWithEmptyEnum(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('enum array must not be empty');
|
||||
|
||||
new EnumSchemaDefinition('Test', []);
|
||||
}
|
||||
|
||||
public function testConstructorWithNonStringEnumValue(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('All enum values must be strings');
|
||||
|
||||
/* @phpstan-ignore argument.type */
|
||||
new EnumSchemaDefinition('Test', ['a', 1, 'b']);
|
||||
}
|
||||
|
||||
public function testConstructorWithEnumNamesMismatch(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('enumNames length must match enum length');
|
||||
|
||||
new EnumSchemaDefinition(
|
||||
title: 'Test',
|
||||
enum: ['a', 'b', 'c'],
|
||||
enumNames: ['A', 'B'],
|
||||
);
|
||||
}
|
||||
|
||||
public function testConstructorWithInvalidDefault(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Default value "invalid" is not in the enum array');
|
||||
|
||||
new EnumSchemaDefinition(
|
||||
title: 'Test',
|
||||
enum: ['a', 'b', 'c'],
|
||||
default: 'invalid',
|
||||
);
|
||||
}
|
||||
|
||||
public function testFromArrayWithMinimalParams(): void
|
||||
{
|
||||
$schema = EnumSchemaDefinition::fromArray([
|
||||
'title' => 'Rating',
|
||||
'enum' => ['1', '2', '3'],
|
||||
]);
|
||||
|
||||
$this->assertSame('Rating', $schema->title);
|
||||
$this->assertSame(['1', '2', '3'], $schema->enum);
|
||||
}
|
||||
|
||||
public function testFromArrayWithAllParams(): void
|
||||
{
|
||||
$schema = EnumSchemaDefinition::fromArray([
|
||||
'title' => 'Satisfaction',
|
||||
'enum' => ['poor', 'fair', 'good'],
|
||||
'description' => 'Rate your satisfaction',
|
||||
'default' => 'fair',
|
||||
'enumNames' => ['Poor', 'Fair', 'Good'],
|
||||
]);
|
||||
|
||||
$this->assertSame('Satisfaction', $schema->title);
|
||||
$this->assertSame(['poor', 'fair', 'good'], $schema->enum);
|
||||
$this->assertSame('Rate your satisfaction', $schema->description);
|
||||
$this->assertSame('fair', $schema->default);
|
||||
$this->assertSame(['Poor', 'Fair', 'Good'], $schema->enumNames);
|
||||
}
|
||||
|
||||
public function testFromArrayWithMissingTitle(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Missing or invalid "title"');
|
||||
|
||||
/* @phpstan-ignore argument.type */
|
||||
EnumSchemaDefinition::fromArray(['enum' => ['a', 'b']]);
|
||||
}
|
||||
|
||||
public function testFromArrayWithMissingEnum(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Missing or invalid "enum"');
|
||||
|
||||
/* @phpstan-ignore argument.type */
|
||||
EnumSchemaDefinition::fromArray(['title' => 'Test']);
|
||||
}
|
||||
|
||||
public function testJsonSerializeWithMinimalParams(): void
|
||||
{
|
||||
$schema = new EnumSchemaDefinition('Rating', ['1', '2', '3']);
|
||||
|
||||
$this->assertSame([
|
||||
'type' => 'string',
|
||||
'title' => 'Rating',
|
||||
'enum' => ['1', '2', '3'],
|
||||
], $schema->jsonSerialize());
|
||||
}
|
||||
|
||||
public function testJsonSerializeWithAllParams(): void
|
||||
{
|
||||
$schema = new EnumSchemaDefinition(
|
||||
title: 'Satisfaction',
|
||||
enum: ['poor', 'fair', 'good'],
|
||||
description: 'Rate your satisfaction',
|
||||
default: 'fair',
|
||||
enumNames: ['Poor', 'Fair', 'Good'],
|
||||
);
|
||||
|
||||
$this->assertSame([
|
||||
'type' => 'string',
|
||||
'title' => 'Satisfaction',
|
||||
'enum' => ['poor', 'fair', 'good'],
|
||||
'description' => 'Rate your satisfaction',
|
||||
'default' => 'fair',
|
||||
'enumNames' => ['Poor', 'Fair', 'Good'],
|
||||
], $schema->jsonSerialize());
|
||||
}
|
||||
}
|
||||
193
tests/Unit/Schema/Elicitation/NumberSchemaDefinitionTest.php
Normal file
193
tests/Unit/Schema/Elicitation/NumberSchemaDefinitionTest.php
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Elicitation;
|
||||
|
||||
use Mcp\Exception\InvalidArgumentException;
|
||||
use Mcp\Schema\Elicitation\NumberSchemaDefinition;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class NumberSchemaDefinitionTest extends TestCase
|
||||
{
|
||||
public function testConstructorWithMinimalParams(): void
|
||||
{
|
||||
$schema = new NumberSchemaDefinition('Age');
|
||||
|
||||
$this->assertSame('Age', $schema->title);
|
||||
$this->assertFalse($schema->integerOnly);
|
||||
$this->assertNull($schema->description);
|
||||
$this->assertNull($schema->default);
|
||||
$this->assertNull($schema->minimum);
|
||||
$this->assertNull($schema->maximum);
|
||||
}
|
||||
|
||||
public function testConstructorWithAllParams(): void
|
||||
{
|
||||
$schema = new NumberSchemaDefinition(
|
||||
title: 'Party Size',
|
||||
integerOnly: true,
|
||||
description: 'Number of guests',
|
||||
default: 2,
|
||||
minimum: 1,
|
||||
maximum: 10,
|
||||
);
|
||||
|
||||
$this->assertSame('Party Size', $schema->title);
|
||||
$this->assertTrue($schema->integerOnly);
|
||||
$this->assertSame('Number of guests', $schema->description);
|
||||
$this->assertSame(2, $schema->default);
|
||||
$this->assertSame(1, $schema->minimum);
|
||||
$this->assertSame(10, $schema->maximum);
|
||||
}
|
||||
|
||||
public function testConstructorWithFloatValues(): void
|
||||
{
|
||||
$schema = new NumberSchemaDefinition(
|
||||
title: 'Temperature',
|
||||
default: 36.5,
|
||||
minimum: 35.0,
|
||||
maximum: 42.0,
|
||||
);
|
||||
|
||||
$this->assertSame(36.5, $schema->default);
|
||||
$this->assertSame(35.0, $schema->minimum);
|
||||
$this->assertSame(42.0, $schema->maximum);
|
||||
}
|
||||
|
||||
public function testConstructorWithMinimumGreaterThanMaximum(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('minimum cannot be greater than maximum');
|
||||
|
||||
new NumberSchemaDefinition('Test', minimum: 10, maximum: 5);
|
||||
}
|
||||
|
||||
public function testConstructorWithDefaultBelowMinimum(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('default value cannot be less than minimum');
|
||||
|
||||
new NumberSchemaDefinition('Test', default: 5, minimum: 10);
|
||||
}
|
||||
|
||||
public function testConstructorWithDefaultAboveMaximum(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('default value cannot be greater than maximum');
|
||||
|
||||
new NumberSchemaDefinition('Test', default: 15, maximum: 10);
|
||||
}
|
||||
|
||||
public function testConstructorWithNonIntegerDefaultWhenIntegerOnly(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('default value must be an integer when integerOnly is true');
|
||||
|
||||
new NumberSchemaDefinition('Test', integerOnly: true, default: 5.5);
|
||||
}
|
||||
|
||||
public function testFromArrayWithIntegerType(): void
|
||||
{
|
||||
$schema = NumberSchemaDefinition::fromArray([
|
||||
'type' => 'integer',
|
||||
'title' => 'Count',
|
||||
]);
|
||||
|
||||
$this->assertTrue($schema->integerOnly);
|
||||
}
|
||||
|
||||
public function testFromArrayWithNumberType(): void
|
||||
{
|
||||
$schema = NumberSchemaDefinition::fromArray([
|
||||
'type' => 'number',
|
||||
'title' => 'Price',
|
||||
]);
|
||||
|
||||
$this->assertFalse($schema->integerOnly);
|
||||
}
|
||||
|
||||
public function testFromArrayWithAllParams(): void
|
||||
{
|
||||
$schema = NumberSchemaDefinition::fromArray([
|
||||
'type' => 'integer',
|
||||
'title' => 'Party Size',
|
||||
'description' => 'Number of guests',
|
||||
'default' => 2,
|
||||
'minimum' => 1,
|
||||
'maximum' => 10,
|
||||
]);
|
||||
|
||||
$this->assertSame('Party Size', $schema->title);
|
||||
$this->assertTrue($schema->integerOnly);
|
||||
$this->assertSame('Number of guests', $schema->description);
|
||||
$this->assertSame(2, $schema->default);
|
||||
$this->assertSame(1, $schema->minimum);
|
||||
$this->assertSame(10, $schema->maximum);
|
||||
}
|
||||
|
||||
public function testFromArrayWithMissingTitle(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Missing or invalid "title"');
|
||||
|
||||
/* @phpstan-ignore argument.type */
|
||||
NumberSchemaDefinition::fromArray(['type' => 'integer']);
|
||||
}
|
||||
|
||||
public function testJsonSerializeAsInteger(): void
|
||||
{
|
||||
$schema = new NumberSchemaDefinition(
|
||||
title: 'Count',
|
||||
integerOnly: true,
|
||||
);
|
||||
|
||||
$this->assertSame([
|
||||
'type' => 'integer',
|
||||
'title' => 'Count',
|
||||
], $schema->jsonSerialize());
|
||||
}
|
||||
|
||||
public function testJsonSerializeAsNumber(): void
|
||||
{
|
||||
$schema = new NumberSchemaDefinition(
|
||||
title: 'Price',
|
||||
integerOnly: false,
|
||||
);
|
||||
|
||||
$this->assertSame([
|
||||
'type' => 'number',
|
||||
'title' => 'Price',
|
||||
], $schema->jsonSerialize());
|
||||
}
|
||||
|
||||
public function testJsonSerializeWithAllParams(): void
|
||||
{
|
||||
$schema = new NumberSchemaDefinition(
|
||||
title: 'Party Size',
|
||||
integerOnly: true,
|
||||
description: 'Number of guests',
|
||||
default: 2,
|
||||
minimum: 1,
|
||||
maximum: 10,
|
||||
);
|
||||
|
||||
$this->assertSame([
|
||||
'type' => 'integer',
|
||||
'title' => 'Party Size',
|
||||
'description' => 'Number of guests',
|
||||
'default' => 2,
|
||||
'minimum' => 1,
|
||||
'maximum' => 10,
|
||||
], $schema->jsonSerialize());
|
||||
}
|
||||
}
|
||||
115
tests/Unit/Schema/Elicitation/PrimitiveSchemaDefinitionTest.php
Normal file
115
tests/Unit/Schema/Elicitation/PrimitiveSchemaDefinitionTest.php
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Elicitation;
|
||||
|
||||
use Mcp\Exception\InvalidArgumentException;
|
||||
use Mcp\Schema\Elicitation\BooleanSchemaDefinition;
|
||||
use Mcp\Schema\Elicitation\EnumSchemaDefinition;
|
||||
use Mcp\Schema\Elicitation\NumberSchemaDefinition;
|
||||
use Mcp\Schema\Elicitation\PrimitiveSchemaDefinition;
|
||||
use Mcp\Schema\Elicitation\StringSchemaDefinition;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class PrimitiveSchemaDefinitionTest extends TestCase
|
||||
{
|
||||
public function testFromArrayCreatesStringSchema(): void
|
||||
{
|
||||
$schema = PrimitiveSchemaDefinition::fromArray([
|
||||
'type' => 'string',
|
||||
'title' => 'Name',
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(StringSchemaDefinition::class, $schema);
|
||||
$this->assertSame('Name', $schema->title);
|
||||
}
|
||||
|
||||
public function testFromArrayCreatesEnumSchemaForStringWithEnum(): void
|
||||
{
|
||||
$schema = PrimitiveSchemaDefinition::fromArray([
|
||||
'type' => 'string',
|
||||
'title' => 'Rating',
|
||||
'enum' => ['1', '2', '3'],
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(EnumSchemaDefinition::class, $schema);
|
||||
$this->assertSame('Rating', $schema->title);
|
||||
$this->assertSame(['1', '2', '3'], $schema->enum);
|
||||
}
|
||||
|
||||
public function testFromArrayCreatesIntegerSchema(): void
|
||||
{
|
||||
$schema = PrimitiveSchemaDefinition::fromArray([
|
||||
'type' => 'integer',
|
||||
'title' => 'Age',
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(NumberSchemaDefinition::class, $schema);
|
||||
$this->assertSame('Age', $schema->title);
|
||||
$this->assertTrue($schema->integerOnly);
|
||||
}
|
||||
|
||||
public function testFromArrayCreatesNumberSchema(): void
|
||||
{
|
||||
$schema = PrimitiveSchemaDefinition::fromArray([
|
||||
'type' => 'number',
|
||||
'title' => 'Price',
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(NumberSchemaDefinition::class, $schema);
|
||||
$this->assertSame('Price', $schema->title);
|
||||
$this->assertFalse($schema->integerOnly);
|
||||
}
|
||||
|
||||
public function testFromArrayCreatesBooleanSchema(): void
|
||||
{
|
||||
$schema = PrimitiveSchemaDefinition::fromArray([
|
||||
'type' => 'boolean',
|
||||
'title' => 'Confirm',
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(BooleanSchemaDefinition::class, $schema);
|
||||
$this->assertSame('Confirm', $schema->title);
|
||||
}
|
||||
|
||||
public function testFromArrayWithMissingType(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Missing or invalid "type"');
|
||||
|
||||
/* @phpstan-ignore argument.type */
|
||||
PrimitiveSchemaDefinition::fromArray(['title' => 'Test']);
|
||||
}
|
||||
|
||||
public function testFromArrayWithUnsupportedType(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Unsupported primitive type "object"');
|
||||
|
||||
PrimitiveSchemaDefinition::fromArray([
|
||||
'type' => 'object',
|
||||
'title' => 'Test',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testFromArrayWithArrayType(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Unsupported primitive type "array"');
|
||||
|
||||
PrimitiveSchemaDefinition::fromArray([
|
||||
'type' => 'array',
|
||||
'title' => 'Test',
|
||||
]);
|
||||
}
|
||||
}
|
||||
159
tests/Unit/Schema/Elicitation/StringSchemaDefinitionTest.php
Normal file
159
tests/Unit/Schema/Elicitation/StringSchemaDefinitionTest.php
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Elicitation;
|
||||
|
||||
use Mcp\Exception\InvalidArgumentException;
|
||||
use Mcp\Schema\Elicitation\StringSchemaDefinition;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class StringSchemaDefinitionTest extends TestCase
|
||||
{
|
||||
public function testConstructorWithMinimalParams(): void
|
||||
{
|
||||
$schema = new StringSchemaDefinition('Name');
|
||||
|
||||
$this->assertSame('Name', $schema->title);
|
||||
$this->assertNull($schema->description);
|
||||
$this->assertNull($schema->default);
|
||||
$this->assertNull($schema->format);
|
||||
$this->assertNull($schema->minLength);
|
||||
$this->assertNull($schema->maxLength);
|
||||
}
|
||||
|
||||
public function testConstructorWithAllParams(): void
|
||||
{
|
||||
$schema = new StringSchemaDefinition(
|
||||
title: 'Email Address',
|
||||
description: 'Your primary email',
|
||||
default: 'user@example.com',
|
||||
format: 'email',
|
||||
minLength: 5,
|
||||
maxLength: 100,
|
||||
);
|
||||
|
||||
$this->assertSame('Email Address', $schema->title);
|
||||
$this->assertSame('Your primary email', $schema->description);
|
||||
$this->assertSame('user@example.com', $schema->default);
|
||||
$this->assertSame('email', $schema->format);
|
||||
$this->assertSame(5, $schema->minLength);
|
||||
$this->assertSame(100, $schema->maxLength);
|
||||
}
|
||||
|
||||
public function testConstructorWithValidFormats(): void
|
||||
{
|
||||
foreach (['date', 'date-time', 'email', 'uri'] as $format) {
|
||||
$schema = new StringSchemaDefinition('Test', format: $format);
|
||||
$this->assertSame($format, $schema->format);
|
||||
}
|
||||
}
|
||||
|
||||
public function testConstructorWithInvalidFormat(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Invalid format "invalid"');
|
||||
|
||||
new StringSchemaDefinition('Test', format: 'invalid');
|
||||
}
|
||||
|
||||
public function testConstructorWithNegativeMinLength(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('minLength must be non-negative');
|
||||
|
||||
new StringSchemaDefinition('Test', minLength: -1);
|
||||
}
|
||||
|
||||
public function testConstructorWithNegativeMaxLength(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('maxLength must be non-negative');
|
||||
|
||||
new StringSchemaDefinition('Test', maxLength: -1);
|
||||
}
|
||||
|
||||
public function testConstructorWithMinLengthGreaterThanMaxLength(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('minLength cannot be greater than maxLength');
|
||||
|
||||
new StringSchemaDefinition('Test', minLength: 10, maxLength: 5);
|
||||
}
|
||||
|
||||
public function testFromArrayWithMinimalParams(): void
|
||||
{
|
||||
$schema = StringSchemaDefinition::fromArray(['title' => 'Name']);
|
||||
|
||||
$this->assertSame('Name', $schema->title);
|
||||
}
|
||||
|
||||
public function testFromArrayWithAllParams(): void
|
||||
{
|
||||
$schema = StringSchemaDefinition::fromArray([
|
||||
'title' => 'Email Address',
|
||||
'description' => 'Your primary email',
|
||||
'default' => 'user@example.com',
|
||||
'format' => 'email',
|
||||
'minLength' => 5,
|
||||
'maxLength' => 100,
|
||||
]);
|
||||
|
||||
$this->assertSame('Email Address', $schema->title);
|
||||
$this->assertSame('Your primary email', $schema->description);
|
||||
$this->assertSame('user@example.com', $schema->default);
|
||||
$this->assertSame('email', $schema->format);
|
||||
$this->assertSame(5, $schema->minLength);
|
||||
$this->assertSame(100, $schema->maxLength);
|
||||
}
|
||||
|
||||
public function testFromArrayWithMissingTitle(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Missing or invalid "title"');
|
||||
|
||||
/* @phpstan-ignore argument.type */
|
||||
StringSchemaDefinition::fromArray([]);
|
||||
}
|
||||
|
||||
public function testJsonSerializeWithMinimalParams(): void
|
||||
{
|
||||
$schema = new StringSchemaDefinition('Name');
|
||||
|
||||
$this->assertSame([
|
||||
'type' => 'string',
|
||||
'title' => 'Name',
|
||||
], $schema->jsonSerialize());
|
||||
}
|
||||
|
||||
public function testJsonSerializeWithAllParams(): void
|
||||
{
|
||||
$schema = new StringSchemaDefinition(
|
||||
title: 'Email Address',
|
||||
description: 'Your primary email',
|
||||
default: 'user@example.com',
|
||||
format: 'email',
|
||||
minLength: 5,
|
||||
maxLength: 100,
|
||||
);
|
||||
|
||||
$this->assertSame([
|
||||
'type' => 'string',
|
||||
'title' => 'Email Address',
|
||||
'description' => 'Your primary email',
|
||||
'default' => 'user@example.com',
|
||||
'format' => 'email',
|
||||
'minLength' => 5,
|
||||
'maxLength' => 100,
|
||||
], $schema->jsonSerialize());
|
||||
}
|
||||
}
|
||||
52
tests/Unit/Schema/Enum/ElicitActionTest.php
Normal file
52
tests/Unit/Schema/Enum/ElicitActionTest.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Enum;
|
||||
|
||||
use Mcp\Schema\Enum\ElicitAction;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class ElicitActionTest extends TestCase
|
||||
{
|
||||
public function testEnumValues(): void
|
||||
{
|
||||
$this->assertSame('accept', ElicitAction::Accept->value);
|
||||
$this->assertSame('decline', ElicitAction::Decline->value);
|
||||
$this->assertSame('cancel', ElicitAction::Cancel->value);
|
||||
}
|
||||
|
||||
public function testFromValidValues(): void
|
||||
{
|
||||
$this->assertSame(ElicitAction::Accept, ElicitAction::from('accept'));
|
||||
$this->assertSame(ElicitAction::Decline, ElicitAction::from('decline'));
|
||||
$this->assertSame(ElicitAction::Cancel, ElicitAction::from('cancel'));
|
||||
}
|
||||
|
||||
public function testFromInvalidValue(): void
|
||||
{
|
||||
$this->expectException(\ValueError::class);
|
||||
ElicitAction::from('invalid');
|
||||
}
|
||||
|
||||
public function testTryFromValidValues(): void
|
||||
{
|
||||
$this->assertSame(ElicitAction::Accept, ElicitAction::tryFrom('accept'));
|
||||
$this->assertSame(ElicitAction::Decline, ElicitAction::tryFrom('decline'));
|
||||
$this->assertSame(ElicitAction::Cancel, ElicitAction::tryFrom('cancel'));
|
||||
}
|
||||
|
||||
public function testTryFromInvalidValue(): void
|
||||
{
|
||||
$this->assertNull(ElicitAction::tryFrom('invalid'));
|
||||
}
|
||||
}
|
||||
74
tests/Unit/Schema/Request/ElicitRequestTest.php
Normal file
74
tests/Unit/Schema/Request/ElicitRequestTest.php
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Request;
|
||||
|
||||
use Mcp\Schema\Elicitation\ElicitationSchema;
|
||||
use Mcp\Schema\Elicitation\NumberSchemaDefinition;
|
||||
use Mcp\Schema\Elicitation\StringSchemaDefinition;
|
||||
use Mcp\Schema\Request\ElicitRequest;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class ElicitRequestTest extends TestCase
|
||||
{
|
||||
public function testConstructor(): void
|
||||
{
|
||||
$schema = new ElicitationSchema([
|
||||
'name' => new StringSchemaDefinition('Name'),
|
||||
]);
|
||||
|
||||
$request = new ElicitRequest('Please provide your name', $schema);
|
||||
|
||||
$this->assertSame('Please provide your name', $request->message);
|
||||
$this->assertSame($schema, $request->requestedSchema);
|
||||
}
|
||||
|
||||
public function testGetMethod(): void
|
||||
{
|
||||
$this->assertSame('elicitation/create', ElicitRequest::getMethod());
|
||||
}
|
||||
|
||||
public function testJsonSerialization(): void
|
||||
{
|
||||
$schema = new ElicitationSchema(
|
||||
[
|
||||
'name' => new StringSchemaDefinition('Name'),
|
||||
'age' => new NumberSchemaDefinition('Age', integerOnly: true, minimum: 0),
|
||||
],
|
||||
['name'],
|
||||
);
|
||||
|
||||
$request = new ElicitRequest('Please provide your details', $schema);
|
||||
$request = $request->withId(1);
|
||||
|
||||
$json = json_encode($request);
|
||||
$this->assertIsString($json);
|
||||
|
||||
$decoded = json_decode($json, true);
|
||||
$this->assertIsArray($decoded);
|
||||
|
||||
$this->assertSame('2.0', $decoded['jsonrpc']);
|
||||
$this->assertSame('elicitation/create', $decoded['method']);
|
||||
$this->assertArrayHasKey('params', $decoded);
|
||||
|
||||
$params = $decoded['params'];
|
||||
$this->assertSame('Please provide your details', $params['message']);
|
||||
$this->assertArrayHasKey('requestedSchema', $params);
|
||||
|
||||
$requestedSchema = $params['requestedSchema'];
|
||||
$this->assertSame('object', $requestedSchema['type']);
|
||||
$this->assertArrayHasKey('name', $requestedSchema['properties']);
|
||||
$this->assertArrayHasKey('age', $requestedSchema['properties']);
|
||||
$this->assertSame(['name'], $requestedSchema['required']);
|
||||
}
|
||||
}
|
||||
163
tests/Unit/Schema/Result/ElicitResultTest.php
Normal file
163
tests/Unit/Schema/Result/ElicitResultTest.php
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Result;
|
||||
|
||||
use Mcp\Exception\InvalidArgumentException;
|
||||
use Mcp\Schema\Enum\ElicitAction;
|
||||
use Mcp\Schema\Result\ElicitResult;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class ElicitResultTest extends TestCase
|
||||
{
|
||||
public function testConstructorWithAcceptAndContent(): void
|
||||
{
|
||||
$content = ['name' => 'John', 'age' => 30];
|
||||
$result = new ElicitResult(ElicitAction::Accept, $content);
|
||||
|
||||
$this->assertSame(ElicitAction::Accept, $result->action);
|
||||
$this->assertSame($content, $result->content);
|
||||
}
|
||||
|
||||
public function testConstructorWithDecline(): void
|
||||
{
|
||||
$result = new ElicitResult(ElicitAction::Decline);
|
||||
|
||||
$this->assertSame(ElicitAction::Decline, $result->action);
|
||||
$this->assertNull($result->content);
|
||||
}
|
||||
|
||||
public function testConstructorWithCancel(): void
|
||||
{
|
||||
$result = new ElicitResult(ElicitAction::Cancel);
|
||||
|
||||
$this->assertSame(ElicitAction::Cancel, $result->action);
|
||||
$this->assertNull($result->content);
|
||||
}
|
||||
|
||||
public function testFromArrayWithAccept(): void
|
||||
{
|
||||
$result = ElicitResult::fromArray([
|
||||
'action' => 'accept',
|
||||
'content' => ['name' => 'John', 'email' => 'john@example.com'],
|
||||
]);
|
||||
|
||||
$this->assertSame(ElicitAction::Accept, $result->action);
|
||||
$this->assertSame(['name' => 'John', 'email' => 'john@example.com'], $result->content);
|
||||
}
|
||||
|
||||
public function testFromArrayWithDecline(): void
|
||||
{
|
||||
$result = ElicitResult::fromArray([
|
||||
'action' => 'decline',
|
||||
]);
|
||||
|
||||
$this->assertSame(ElicitAction::Decline, $result->action);
|
||||
$this->assertNull($result->content);
|
||||
}
|
||||
|
||||
public function testFromArrayWithCancel(): void
|
||||
{
|
||||
$result = ElicitResult::fromArray([
|
||||
'action' => 'cancel',
|
||||
]);
|
||||
|
||||
$this->assertSame(ElicitAction::Cancel, $result->action);
|
||||
$this->assertNull($result->content);
|
||||
}
|
||||
|
||||
public function testFromArrayWithMissingAction(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Missing or invalid "action"');
|
||||
|
||||
/* @phpstan-ignore argument.type */
|
||||
ElicitResult::fromArray([]);
|
||||
}
|
||||
|
||||
public function testFromArrayWithInvalidAction(): void
|
||||
{
|
||||
$this->expectException(\ValueError::class);
|
||||
|
||||
ElicitResult::fromArray(['action' => 'invalid']);
|
||||
}
|
||||
|
||||
public function testFromArrayWithAcceptActionRequiresContent(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Content must be provided when action is "accept"');
|
||||
|
||||
ElicitResult::fromArray(['action' => 'accept']);
|
||||
}
|
||||
|
||||
public function testIsAccepted(): void
|
||||
{
|
||||
$acceptResult = new ElicitResult(ElicitAction::Accept, ['name' => 'John']);
|
||||
$declineResult = new ElicitResult(ElicitAction::Decline);
|
||||
$cancelResult = new ElicitResult(ElicitAction::Cancel);
|
||||
|
||||
$this->assertTrue($acceptResult->isAccepted());
|
||||
$this->assertFalse($declineResult->isAccepted());
|
||||
$this->assertFalse($cancelResult->isAccepted());
|
||||
}
|
||||
|
||||
public function testIsDeclined(): void
|
||||
{
|
||||
$acceptResult = new ElicitResult(ElicitAction::Accept, ['name' => 'John']);
|
||||
$declineResult = new ElicitResult(ElicitAction::Decline);
|
||||
$cancelResult = new ElicitResult(ElicitAction::Cancel);
|
||||
|
||||
$this->assertFalse($acceptResult->isDeclined());
|
||||
$this->assertTrue($declineResult->isDeclined());
|
||||
$this->assertFalse($cancelResult->isDeclined());
|
||||
}
|
||||
|
||||
public function testIsCancelled(): void
|
||||
{
|
||||
$acceptResult = new ElicitResult(ElicitAction::Accept, ['name' => 'John']);
|
||||
$declineResult = new ElicitResult(ElicitAction::Decline);
|
||||
$cancelResult = new ElicitResult(ElicitAction::Cancel);
|
||||
|
||||
$this->assertFalse($acceptResult->isCancelled());
|
||||
$this->assertFalse($declineResult->isCancelled());
|
||||
$this->assertTrue($cancelResult->isCancelled());
|
||||
}
|
||||
|
||||
public function testJsonSerializeWithAcceptAndContent(): void
|
||||
{
|
||||
$result = new ElicitResult(ElicitAction::Accept, ['name' => 'John', 'age' => 30]);
|
||||
|
||||
$this->assertSame([
|
||||
'action' => 'accept',
|
||||
'content' => ['name' => 'John', 'age' => 30],
|
||||
], $result->jsonSerialize());
|
||||
}
|
||||
|
||||
public function testJsonSerializeWithDecline(): void
|
||||
{
|
||||
$result = new ElicitResult(ElicitAction::Decline);
|
||||
|
||||
$this->assertSame([
|
||||
'action' => 'decline',
|
||||
], $result->jsonSerialize());
|
||||
}
|
||||
|
||||
public function testJsonSerializeWithCancel(): void
|
||||
{
|
||||
$result = new ElicitResult(ElicitAction::Cancel);
|
||||
|
||||
$this->assertSame([
|
||||
'action' => 'cancel',
|
||||
], $result->jsonSerialize());
|
||||
}
|
||||
}
|
||||
|
|
@ -39,12 +39,15 @@ class InitializeHandlerTest extends TestCase
|
|||
$handler = new InitializeHandler($configuration);
|
||||
|
||||
$session = $this->createMock(SessionInterface::class);
|
||||
$session->expects($this->once())
|
||||
$session->expects($this->exactly(2))
|
||||
->method('set')
|
||||
->with('client_info', [
|
||||
'name' => 'client-app',
|
||||
'version' => '1.0.0',
|
||||
]);
|
||||
->willReturnCallback(function (string $key, array $value): void {
|
||||
match ($key) {
|
||||
'client_info' => $this->assertSame(['name' => 'client-app', 'version' => '1.0.0'], $value),
|
||||
'client_capabilities' => $this->assertSame([], $value),
|
||||
default => $this->fail("Unexpected session key: {$key}"),
|
||||
};
|
||||
});
|
||||
|
||||
$request = InitializeRequest::fromArray([
|
||||
'jsonrpc' => MessageInterface::JSONRPC_VERSION,
|
||||
|
|
|
|||
Loading…
Reference in a new issue