From 920cf15982250813b00698e9de8e23878816cc19 Mon Sep 17 00:00:00 2001 From: Christopher Hertel Date: Mon, 26 Jan 2026 20:26:13 +0100 Subject: [PATCH] Update codestyle based on updated Symfony rules --- examples/server/bootstrap.php | 2 +- .../server/client-communication/server.php | 2 +- .../Service/InMemoryTaskRepository.php | 2 +- .../Service/SystemStatsService.php | 2 +- .../UserIdCompletionProvider.php | 2 +- .../server/discovery-userprofile/server.php | 4 +- .../server/env-variables/EnvToolHandler.php | 12 +- .../SchemaShowcaseElements.php | 4 +- .../Completion/EnumCompletionProvider.php | 4 +- .../Completion/ListCompletionProvider.php | 2 +- src/Capability/Discovery/SchemaGenerator.php | 6 +- src/Capability/Discovery/SchemaValidator.php | 16 +-- .../Formatter/ResourceResultFormatter.php | 2 +- src/Capability/Registry.php | 8 +- src/Capability/Registry/ReferenceHandler.php | 18 ++- src/Schema/Annotations.php | 6 +- src/Schema/Prompt.php | 4 +- src/Schema/Result/ListPromptsResult.php | 2 +- .../Result/ListResourceTemplatesResult.php | 2 +- src/Schema/Result/ListResourcesResult.php | 2 +- src/Schema/Result/ListToolsResult.php | 2 +- src/Server/Protocol.php | 11 +- tests/Conformance/server.php | 18 +-- .../Attribute/CompletionProviderFixture.php | 2 +- .../Discovery/HandlerResolverTest.php | 10 +- tests/Unit/Capability/RegistryTest.php | 104 +++++++++--------- .../Handler/Request/CallToolHandlerTest.php | 24 ++-- .../Request/ListPromptsHandlerTest.php | 2 +- .../ListResourceTemplatesHandlerTest.php | 2 +- .../Request/ListResourcesHandlerTest.php | 2 +- .../Handler/Request/ListToolsHandlerTest.php | 2 +- tests/Unit/Server/ProtocolTest.php | 44 ++++---- tests/Unit/ServerTest.php | 8 +- 33 files changed, 165 insertions(+), 168 deletions(-) diff --git a/examples/server/bootstrap.php b/examples/server/bootstrap.php index a9110317..77fa744a 100644 --- a/examples/server/bootstrap.php +++ b/examples/server/bootstrap.php @@ -21,7 +21,7 @@ require_once dirname(__DIR__, 2).'/vendor/autoload.php'; -set_exception_handler(function (Throwable $t): never { +set_exception_handler(static function (Throwable $t): never { logger()->critical('Uncaught exception: '.$t->getMessage(), ['exception' => $t]); exit(1); diff --git a/examples/server/client-communication/server.php b/examples/server/client-communication/server.php index 42e5058b..698993d1 100644 --- a/examples/server/client-communication/server.php +++ b/examples/server/client-communication/server.php @@ -27,7 +27,7 @@ ->setCapabilities(new ServerCapabilities(logging: true, tools: true)) ->setDiscovery(__DIR__) ->addTool( - function (RequestContext $context, string $dataset): array { + static function (RequestContext $context, string $dataset): array { $client = $context->getClientGateway(); $client->log(LoggingLevel::Info, sprintf('Running quality checks on dataset "%s"', $dataset)); diff --git a/examples/server/custom-dependencies/Service/InMemoryTaskRepository.php b/examples/server/custom-dependencies/Service/InMemoryTaskRepository.php index 95f77912..2c67af62 100644 --- a/examples/server/custom-dependencies/Service/InMemoryTaskRepository.php +++ b/examples/server/custom-dependencies/Service/InMemoryTaskRepository.php @@ -50,7 +50,7 @@ public function addTask(string $userId, string $description): array public function getTasksForUser(string $userId): array { - return array_values(array_filter($this->tasks, fn ($task) => $task['userId'] === $userId && !$task['completed'])); + return array_values(array_filter($this->tasks, static fn ($task) => $task['userId'] === $userId && !$task['completed'])); } public function getAllTasks(): array diff --git a/examples/server/custom-dependencies/Service/SystemStatsService.php b/examples/server/custom-dependencies/Service/SystemStatsService.php index 1cc9beed..e41b6a24 100644 --- a/examples/server/custom-dependencies/Service/SystemStatsService.php +++ b/examples/server/custom-dependencies/Service/SystemStatsService.php @@ -21,7 +21,7 @@ public function __construct( public function getSystemStats(): array { $allTasks = $this->taskRepository->getAllTasks(); - $completed = \count(array_filter($allTasks, fn ($task) => $task['completed'])); + $completed = \count(array_filter($allTasks, static fn ($task) => $task['completed'])); $pending = \count($allTasks) - $completed; return [ diff --git a/examples/server/discovery-userprofile/UserIdCompletionProvider.php b/examples/server/discovery-userprofile/UserIdCompletionProvider.php index 03d97ef3..bee4ffa6 100644 --- a/examples/server/discovery-userprofile/UserIdCompletionProvider.php +++ b/examples/server/discovery-userprofile/UserIdCompletionProvider.php @@ -19,6 +19,6 @@ final class UserIdCompletionProvider implements ProviderInterface public function getCompletions(string $currentValue): array { - return array_filter(self::AVAILABLE_USER_IDS, fn (string $userId) => str_contains($userId, $currentValue)); + return array_filter(self::AVAILABLE_USER_IDS, static fn (string $userId) => str_contains($userId, $currentValue)); } } diff --git a/examples/server/discovery-userprofile/server.php b/examples/server/discovery-userprofile/server.php index 48033716..25448188 100644 --- a/examples/server/discovery-userprofile/server.php +++ b/examples/server/discovery-userprofile/server.php @@ -23,7 +23,7 @@ ->setSession(new FileSessionStore(__DIR__.'/sessions')) ->setDiscovery(__DIR__) ->addTool( - function (float $a, float $b, string $operation = 'add'): array { + static function (float $a, float $b, string $operation = 'add'): array { $result = match ($operation) { 'add' => $a + $b, 'subtract' => $a - $b, @@ -42,7 +42,7 @@ function (float $a, float $b, string $operation = 'add'): array { description: 'Perform basic math operations (add, subtract, multiply, divide)' ) ->addResource( - function (): array { + static function (): array { $memoryUsage = memory_get_usage(true); $memoryPeak = memory_get_peak_usage(true); $uptime = time() - ($_SERVER['REQUEST_TIME_FLOAT'] ?? time()); diff --git a/examples/server/env-variables/EnvToolHandler.php b/examples/server/env-variables/EnvToolHandler.php index c11c6633..0520a715 100644 --- a/examples/server/env-variables/EnvToolHandler.php +++ b/examples/server/env-variables/EnvToolHandler.php @@ -64,12 +64,12 @@ public function processData(string $input): array 'processed_input_length' => \strlen($input), 'message' => 'Processed in PRODUCTION mode (summary only).', ]; - } else { - return [ - 'mode' => $appMode ?: 'default', - 'original_input' => $input, - 'message' => 'Processed in default mode (APP_MODE not recognized or not set).', - ]; } + + return [ + 'mode' => $appMode ?: 'default', + 'original_input' => $input, + 'message' => 'Processed in default mode (APP_MODE not recognized or not set).', + ]; } } diff --git a/examples/server/schema-showcase/SchemaShowcaseElements.php b/examples/server/schema-showcase/SchemaShowcaseElements.php index 35671cf1..294d9680 100644 --- a/examples/server/schema-showcase/SchemaShowcaseElements.php +++ b/examples/server/schema-showcase/SchemaShowcaseElements.php @@ -267,10 +267,10 @@ enum: ['sort', 'reverse', 'shuffle', 'deduplicate', 'filter_short', 'filter_long $processed = array_unique($processed); break; case 'filter_short': - $processed = array_filter($processed, fn ($item) => \strlen($item) <= 10); + $processed = array_filter($processed, static fn ($item) => \strlen($item) <= 10); break; case 'filter_long': - $processed = array_filter($processed, fn ($item) => \strlen($item) > 10); + $processed = array_filter($processed, static fn ($item) => \strlen($item) > 10); break; } diff --git a/src/Capability/Completion/EnumCompletionProvider.php b/src/Capability/Completion/EnumCompletionProvider.php index 4c2a014f..7864e4e6 100644 --- a/src/Capability/Completion/EnumCompletionProvider.php +++ b/src/Capability/Completion/EnumCompletionProvider.php @@ -33,7 +33,7 @@ public function __construct(string $enumClass) } $this->values = array_map( - fn ($case) => isset($case->value) && \is_string($case->value) ? $case->value : $case->name, + static fn ($case) => isset($case->value) && \is_string($case->value) ? $case->value : $case->name, $enumClass::cases() ); } @@ -46,7 +46,7 @@ public function getCompletions(string $currentValue): array return array_values(array_filter( $this->values, - fn (string $value) => str_starts_with($value, $currentValue) + static fn (string $value) => str_starts_with($value, $currentValue) )); } } diff --git a/src/Capability/Completion/ListCompletionProvider.php b/src/Capability/Completion/ListCompletionProvider.php index 05e7811c..5d48f4bd 100644 --- a/src/Capability/Completion/ListCompletionProvider.php +++ b/src/Capability/Completion/ListCompletionProvider.php @@ -32,7 +32,7 @@ public function getCompletions(string $currentValue): array return array_values(array_filter( $this->values, - fn (string $value) => str_starts_with($value, $currentValue) + static fn (string $value) => str_starts_with($value, $currentValue) )); } } diff --git a/src/Capability/Discovery/SchemaGenerator.php b/src/Capability/Discovery/SchemaGenerator.php index 225215dc..dab9cbb5 100644 --- a/src/Capability/Discovery/SchemaGenerator.php +++ b/src/Capability/Discovery/SchemaGenerator.php @@ -311,7 +311,7 @@ private function buildVariadicParameterSchema(array $paramInfo): array // If no items specified by Schema attribute, infer from type if (!isset($paramSchema['items'])) { $itemJsonTypes = $this->mapPhpTypeToJsonSchemaType($paramInfo['type_string']); - $nonNullItemTypes = array_filter($itemJsonTypes, fn ($t) => 'null' !== $t); + $nonNullItemTypes = array_filter($itemJsonTypes, static fn ($t) => 'null' !== $t); if (1 === \count($nonNullItemTypes)) { $paramSchema['items'] = ['type' => $nonNullItemTypes[0]]; @@ -574,7 +574,7 @@ private function getTypeStringFromReflection(?\ReflectionType $type, bool $nativ $types[] = $this->getTypeStringFromReflection($innerType, $innerType->allowsNull()); } if ($nativeAllowsNull) { - $types = array_filter($types, fn ($t) => 'null' !== strtolower($t)); + $types = array_filter($types, static fn ($t) => 'null' !== strtolower($t)); } $typeString = implode('|', array_unique(array_filter($types))); } elseif ($type instanceof \ReflectionIntersectionType) { @@ -619,7 +619,7 @@ private function getTypeStringFromReflection(?\ReflectionType $type, bool $nativ // Remove leading backslash from class names, but handle built-ins like 'int' or unions like 'int|string' if (str_contains($typeString, '\\')) { $parts = preg_split('/([|&])/', $typeString, -1, \PREG_SPLIT_DELIM_CAPTURE); - $processedParts = array_map(fn ($part) => str_starts_with($part, '\\') ? ltrim($part, '\\') : $part, $parts); + $processedParts = array_map(static fn ($part) => str_starts_with($part, '\\') ? ltrim($part, '\\') : $part, $parts); $typeString = implode('', $processedParts); } diff --git a/src/Capability/Discovery/SchemaValidator.php b/src/Capability/Discovery/SchemaValidator.php index a6a37b35..c0432a02 100644 --- a/src/Capability/Discovery/SchemaValidator.php +++ b/src/Capability/Discovery/SchemaValidator.php @@ -145,10 +145,10 @@ private function convertDataForValidator(mixed $data): mixed } return $obj; - } else { - // It's a list (sequential array), convert items recursively - return array_map([$this, 'convertDataForValidator'], $data); } + + // It's a list (sequential array), convert items recursively + return array_map([$this, 'convertDataForValidator'], $data); } elseif (\is_object($data) && $data instanceof \stdClass) { // Deep copy/convert stdClass objects as well $obj = new \stdClass(); @@ -194,7 +194,7 @@ private function formatJsonPointerPath(?array $pathComponents): string if (empty($pathComponents)) { return '/'; } - $escapedComponents = array_map(function ($component) { + $escapedComponents = array_map(static function ($component) { $componentStr = (string) $component; return str_replace(['~', '/'], ['~0', '~1'], $componentStr); @@ -215,7 +215,7 @@ private function formatValidationError(ValidationError $error): string switch (strtolower($keyword)) { case 'required': $missing = $args['missing'] ?? []; - $formattedMissing = implode(', ', array_map(fn ($p) => "`{$p}`", $missing)); + $formattedMissing = implode(', ', array_map(static fn ($p) => "`{$p}`", $missing)); $message = "Missing required properties: {$formattedMissing}."; break; case 'type': @@ -236,7 +236,7 @@ private function formatValidationError(ValidationError $error): string if (empty($allowedValues)) { $message = 'Value does not match the allowed enumeration.'; } else { - $formattedAllowed = array_map(function ($v) { /* ... formatting logic ... */ + $formattedAllowed = array_map(static function ($v) { /* ... formatting logic ... */ if (\is_string($v)) { return '"'.$v.'"'; } @@ -309,7 +309,7 @@ private function formatValidationError(ValidationError $error): string break; case 'additionalProperties': // Corrected casing $unexpected = $args['properties'] ?? []; - $formattedUnexpected = implode(', ', array_map(fn ($p) => "`{$p}`", $unexpected)); + $formattedUnexpected = implode(', ', array_map(static fn ($p) => "`{$p}`", $unexpected)); $message = "Object contains unexpected additional properties: {$formattedUnexpected}."; break; case 'format': @@ -320,7 +320,7 @@ private function formatValidationError(ValidationError $error): string $builtInMessage = $error->message(); if ($builtInMessage && 'The data must match the schema' !== $builtInMessage) { $placeholders = $args; - $builtInMessage = preg_replace_callback('/\{(\w+)\}/', function ($match) use ($placeholders) { + $builtInMessage = preg_replace_callback('/\{(\w+)\}/', static function ($match) use ($placeholders) { $key = $match[1]; $value = $placeholders[$key] ?? '{'.$key.'}'; diff --git a/src/Capability/Formatter/ResourceResultFormatter.php b/src/Capability/Formatter/ResourceResultFormatter.php index 330590ee..bac2bc77 100644 --- a/src/Capability/Formatter/ResourceResultFormatter.php +++ b/src/Capability/Formatter/ResourceResultFormatter.php @@ -86,7 +86,7 @@ public function format(mixed $readResult, string $uri, ?string $mimeType = null, } if ($allAreEmbeddedResource && $hasEmbeddedResource) { - return array_map(fn ($item) => $item->resource, $readResult); + return array_map(static fn ($item) => $item->resource, $readResult); } if ($hasResourceContents || $hasEmbeddedResource) { diff --git a/src/Capability/Registry.php b/src/Capability/Registry.php index 7a6f0d45..08348e8a 100644 --- a/src/Capability/Registry.php +++ b/src/Capability/Registry.php @@ -344,10 +344,10 @@ public function getPrompt(string $name): PromptReference public function getDiscoveryState(): DiscoveryState { return new DiscoveryState( - tools: array_filter($this->tools, fn ($tool) => !$tool->isManual), - resources: array_filter($this->resources, fn ($resource) => !$resource->isManual), - prompts: array_filter($this->prompts, fn ($prompt) => !$prompt->isManual), - resourceTemplates: array_filter($this->resourceTemplates, fn ($template) => !$template->isManual), + tools: array_filter($this->tools, static fn ($tool) => !$tool->isManual), + resources: array_filter($this->resources, static fn ($resource) => !$resource->isManual), + prompts: array_filter($this->prompts, static fn ($prompt) => !$prompt->isManual), + resourceTemplates: array_filter($this->resourceTemplates, static fn ($template) => !$template->isManual), ); } diff --git a/src/Capability/Registry/ReferenceHandler.php b/src/Capability/Registry/ReferenceHandler.php index f01b1870..7b4a0cdc 100644 --- a/src/Capability/Registry/ReferenceHandler.php +++ b/src/Capability/Registry/ReferenceHandler.php @@ -185,19 +185,17 @@ private function castArgumentType(mixed $argument, \ReflectionParameter $paramet } return $value; - } else { - if (\is_string($argument)) { - foreach ($typeName::cases() as $case) { - if ($case->name === $argument) { - return $case; - } + } + if (\is_string($argument)) { + foreach ($typeName::cases() as $case) { + if ($case->name === $argument) { + return $case; } - $validNames = array_map(fn ($c) => $c->name, $typeName::cases()); - throw new InvalidArgumentException("Invalid value '{$argument}' for unit enum {$typeName}. Expected one of: ".implode(', ', $validNames).'.'); - } else { - throw new InvalidArgumentException("Invalid value type '{$argument}' for unit enum {$typeName}. Expected a string matching a case name."); } + $validNames = array_map(static fn ($c) => $c->name, $typeName::cases()); + throw new InvalidArgumentException("Invalid value '{$argument}' for unit enum {$typeName}. Expected one of: ".implode(', ', $validNames).'.'); } + throw new InvalidArgumentException("Invalid value type '{$argument}' for unit enum {$typeName}. Expected a string matching a case name."); } try { diff --git a/src/Schema/Annotations.php b/src/Schema/Annotations.php index b07e2343..a448ba53 100644 --- a/src/Schema/Annotations.php +++ b/src/Schema/Annotations.php @@ -46,7 +46,7 @@ public function __construct( } if (null !== $this->audience) { foreach ($this->audience as $role) { - if (!($role instanceof Role)) { + if (!$role instanceof Role) { throw new InvalidArgumentException('All audience members must be instances of Role enum.'); } } @@ -60,7 +60,7 @@ public static function fromArray(array $data): self { $audience = null; if (isset($data['audience']) && \is_array($data['audience'])) { - $audience = array_map(fn (string $r) => Role::from($r), $data['audience']); + $audience = array_map(static fn (string $r) => Role::from($r), $data['audience']); } return new self( @@ -76,7 +76,7 @@ public function jsonSerialize(): array { $data = []; if (null !== $this->audience) { - $data['audience'] = array_map(fn (Role $r) => $r->value, $this->audience); + $data['audience'] = array_map(static fn (Role $r) => $r->value, $this->audience); } if (null !== $this->priority) { $data['priority'] = $this->priority; diff --git a/src/Schema/Prompt.php b/src/Schema/Prompt.php index 0fe41586..45e37f01 100644 --- a/src/Schema/Prompt.php +++ b/src/Schema/Prompt.php @@ -47,7 +47,7 @@ public function __construct( ) { if (null !== $this->arguments) { foreach ($this->arguments as $arg) { - if (!($arg instanceof PromptArgument)) { + if (!$arg instanceof PromptArgument) { throw new InvalidArgumentException('All items in Prompt "arguments" must be PromptArgument instances.'); } } @@ -64,7 +64,7 @@ public static function fromArray(array $data): self } $arguments = null; if (isset($data['arguments']) && \is_array($data['arguments'])) { - $arguments = array_map(fn (array $argData) => PromptArgument::fromArray($argData), $data['arguments']); + $arguments = array_map(static fn (array $argData) => PromptArgument::fromArray($argData), $data['arguments']); } if (!empty($data['_meta']) && !\is_array($data['_meta'])) { diff --git a/src/Schema/Result/ListPromptsResult.php b/src/Schema/Result/ListPromptsResult.php index 3a2fa1f0..7b1b3823 100644 --- a/src/Schema/Result/ListPromptsResult.php +++ b/src/Schema/Result/ListPromptsResult.php @@ -50,7 +50,7 @@ public static function fromArray(array $data): self } return new self( - array_map(fn (array $prompt) => Prompt::fromArray($prompt), $data['prompts']), + array_map(static fn (array $prompt) => Prompt::fromArray($prompt), $data['prompts']), $data['nextCursor'] ?? null ); } diff --git a/src/Schema/Result/ListResourceTemplatesResult.php b/src/Schema/Result/ListResourceTemplatesResult.php index 97a37322..1b8ddb2b 100644 --- a/src/Schema/Result/ListResourceTemplatesResult.php +++ b/src/Schema/Result/ListResourceTemplatesResult.php @@ -50,7 +50,7 @@ public static function fromArray(array $data): self } return new self( - array_map(fn (array $resourceTemplate) => ResourceTemplate::fromArray($resourceTemplate), $data['resourceTemplates']), + array_map(static fn (array $resourceTemplate) => ResourceTemplate::fromArray($resourceTemplate), $data['resourceTemplates']), $data['nextCursor'] ?? null ); } diff --git a/src/Schema/Result/ListResourcesResult.php b/src/Schema/Result/ListResourcesResult.php index aa005639..50fa9bfe 100644 --- a/src/Schema/Result/ListResourcesResult.php +++ b/src/Schema/Result/ListResourcesResult.php @@ -50,7 +50,7 @@ public static function fromArray(array $data): self } return new self( - array_map(fn (array $resource) => ResourceSchema::fromArray($resource), $data['resources']), + array_map(static fn (array $resource) => ResourceSchema::fromArray($resource), $data['resources']), $data['nextCursor'] ?? null ); } diff --git a/src/Schema/Result/ListToolsResult.php b/src/Schema/Result/ListToolsResult.php index 176c86a9..7b08a0de 100644 --- a/src/Schema/Result/ListToolsResult.php +++ b/src/Schema/Result/ListToolsResult.php @@ -50,7 +50,7 @@ public static function fromArray(array $data): self } return new self( - array_map(fn (array $tool) => Tool::fromArray($tool), $data['tools']), + array_map(static fn (array $tool) => Tool::fromArray($tool), $data['tools']), $data['nextCursor'] ?? null ); } diff --git a/src/Server/Protocol.php b/src/Server/Protocol.php index 5c2d1f0c..feedae3b 100644 --- a/src/Server/Protocol.php +++ b/src/Server/Protocol.php @@ -173,7 +173,7 @@ private function handleRequest(TransportInterface $transport, Request $request, try { /** @var McpFiber $fiber */ - $fiber = new \Fiber(fn () => $handler->handle($request, $session)); + $fiber = new \Fiber(static fn () => $handler->handle($request, $session)); $result = $fiber->start(); @@ -192,11 +192,10 @@ private function handleRequest(TransportInterface $transport, Request $request, $transport->attachFiberToSession($fiber, $session->getId()); return; - } else { - $finalResult = $fiber->getReturn(); - - $this->sendResponse($transport, $finalResult, $session); } + $finalResult = $fiber->getReturn(); + + $this->sendResponse($transport, $finalResult, $session); } catch (\InvalidArgumentException $e) { $this->logger->warning(\sprintf('Invalid argument: %s', $e->getMessage()), ['exception' => $e]); @@ -581,7 +580,7 @@ private function gcSessions(): void if (!empty($deletedSessions)) { $this->logger->debug('Garbage collected expired sessions.', [ 'count' => \count($deletedSessions), - 'session_ids' => array_map(fn (Uuid $id) => $id->toRfc4122(), $deletedSessions), + 'session_ids' => array_map(static fn (Uuid $id) => $id->toRfc4122(), $deletedSessions), ]); } } diff --git a/tests/Conformance/server.php b/tests/Conformance/server.php index 802fa05a..bbcbaa10 100644 --- a/tests/Conformance/server.php +++ b/tests/Conformance/server.php @@ -38,23 +38,23 @@ ->setSession(new FileSessionStore(__DIR__.'/sessions')) ->setLogger($logger) // Tools - ->addTool(fn () => 'This is a simple text response for testing.', 'test_simple_text', 'Tests simple text content response') - ->addTool(fn () => new ImageContent(Elements::TEST_IMAGE_BASE64, 'image/png'), 'test_image_content', 'Tests image content response') - ->addTool(fn () => new AudioContent(Elements::TEST_AUDIO_BASE64, 'audio/wav'), 'test_audio_content', 'Tests audio content response') - ->addTool(fn () => EmbeddedResource::fromText('test://embedded-resource', 'This is an embedded resource content.'), 'test_embedded_resource', 'Tests embedded resource content response') + ->addTool(static fn () => 'This is a simple text response for testing.', 'test_simple_text', 'Tests simple text content response') + ->addTool(static fn () => new ImageContent(Elements::TEST_IMAGE_BASE64, 'image/png'), 'test_image_content', 'Tests image content response') + ->addTool(static fn () => new AudioContent(Elements::TEST_AUDIO_BASE64, 'audio/wav'), 'test_audio_content', 'Tests audio content response') + ->addTool(static fn () => EmbeddedResource::fromText('test://embedded-resource', 'This is an embedded resource content.'), 'test_embedded_resource', 'Tests embedded resource content response') ->addTool([Elements::class, 'toolMultipleTypes'], 'test_multiple_content_types', 'Tests response with multiple content types') ->addTool([Elements::class, 'toolWithLogging'], 'test_tool_with_logging', 'Tests tool that emits log messages') ->addTool([Elements::class, 'toolWithProgress'], 'test_tool_with_progress', 'Tests tool that reports progress notifications') ->addTool([Elements::class, 'toolWithSampling'], 'test_sampling', 'Tests server-initiated sampling') - ->addTool(fn () => CallToolResult::error([new TextContent('This tool intentionally returns an error for testing')]), 'test_error_handling', 'Tests error response handling') + ->addTool(static fn () => CallToolResult::error([new TextContent('This tool intentionally returns an error for testing')]), 'test_error_handling', 'Tests error response handling') // Resources - ->addResource(fn () => 'This is the content of the static text resource.', 'test://static-text', 'static-text', 'A static text resource for testing') - ->addResource(fn () => fopen('data://image/png;base64,'.Elements::TEST_IMAGE_BASE64, 'r'), 'test://static-binary', 'static-binary', 'A static binary resource (image) for testing') + ->addResource(static fn () => 'This is the content of the static text resource.', 'test://static-text', 'static-text', 'A static text resource for testing') + ->addResource(static fn () => fopen('data://image/png;base64,'.Elements::TEST_IMAGE_BASE64, 'r'), 'test://static-binary', 'static-binary', 'A static binary resource (image) for testing') ->addResourceTemplate([Elements::class, 'resourceTemplate'], 'test://template/{id}/data', 'template', 'A resource template with parameter substitution', 'application/json') // TODO: Handler for resources/subscribe and resources/unsubscribe - ->addResource(fn () => 'Watched resource content', 'test://watched-resource', 'watched-resource', 'A resource that can be watched') + ->addResource(static fn () => 'Watched resource content', 'test://watched-resource', 'watched-resource', 'A resource that can be watched') // Prompts - ->addPrompt(fn () => [['role' => 'user', 'content' => 'This is a simple prompt for testing.']], 'test_simple_prompt', 'A simple prompt without arguments') + ->addPrompt(static fn () => [['role' => 'user', 'content' => 'This is a simple prompt for testing.']], 'test_simple_prompt', 'A simple prompt without arguments') ->addPrompt([Elements::class, 'promptWithArguments'], 'test_prompt_with_arguments', 'A prompt with required arguments') ->addPrompt([Elements::class, 'promptWithEmbeddedResource'], 'test_prompt_with_embedded_resource', 'A prompt that includes an embedded resource') ->addPrompt([Elements::class, 'promptWithImage'], 'test_prompt_with_image', 'A prompt that includes image content') diff --git a/tests/Unit/Capability/Attribute/CompletionProviderFixture.php b/tests/Unit/Capability/Attribute/CompletionProviderFixture.php index 6c623cf7..1f4f649e 100644 --- a/tests/Unit/Capability/Attribute/CompletionProviderFixture.php +++ b/tests/Unit/Capability/Attribute/CompletionProviderFixture.php @@ -25,6 +25,6 @@ public function getCompletions(string $currentValue): array { self::$lastCurrentValue = $currentValue; - return array_filter(self::$completions, fn ($item) => str_starts_with($item, $currentValue)); + return array_filter(self::$completions, static fn ($item) => str_starts_with($item, $currentValue)); } } diff --git a/tests/Unit/Capability/Discovery/HandlerResolverTest.php b/tests/Unit/Capability/Discovery/HandlerResolverTest.php index 18347d3f..53188bf7 100644 --- a/tests/Unit/Capability/Discovery/HandlerResolverTest.php +++ b/tests/Unit/Capability/Discovery/HandlerResolverTest.php @@ -19,7 +19,7 @@ class HandlerResolverTest extends TestCase { public function testResolvesClosuresToReflectionFunction() { - $closure = function (string $input): string { + $closure = static function (string $input): string { return "processed: $input"; }; $resolved = HandlerResolver::resolve($closure); @@ -135,13 +135,13 @@ public function testThrowsForAbstractMethodHandler() public function testResolvesClosuresWithDifferentSignatures() { - $noParams = function () { + $noParams = static function () { return 'test'; }; - $withParams = function (int $a, string $b = 'default') { + $withParams = static function (int $a, string $b = 'default') { return $a.$b; }; - $variadic = function (...$args) { + $variadic = static function (...$args) { return $args; }; $this->assertInstanceOf(\ReflectionFunction::class, HandlerResolver::resolve($noParams)); @@ -154,7 +154,7 @@ public function testResolvesClosuresWithDifferentSignatures() public function testDistinguishesBetweenClosuresAndCallableArrays() { - $closure = function () { + $closure = static function () { return 'closure'; }; $array = [ValidHandlerClass::class, 'publicMethod']; diff --git a/tests/Unit/Capability/RegistryTest.php b/tests/Unit/Capability/RegistryTest.php index a5e1647c..e8b19585 100644 --- a/tests/Unit/Capability/RegistryTest.php +++ b/tests/Unit/Capability/RegistryTest.php @@ -50,7 +50,7 @@ public function testHasserReturnFalseForEmptyRegistry(): void public function testHasToolsReturnsTrueWhenToolIsRegistered(): void { $tool = $this->createValidTool('test_tool'); - $this->registry->registerTool($tool, fn () => 'result'); + $this->registry->registerTool($tool, static fn () => 'result'); $this->assertTrue($this->registry->hasTools()); } @@ -60,8 +60,8 @@ public function testGetToolsReturnsAllRegisteredTools(): void $tool1 = $this->createValidTool('tool1'); $tool2 = $this->createValidTool('tool2'); - $this->registry->registerTool($tool1, fn () => 'result1'); - $this->registry->registerTool($tool2, fn () => 'result2'); + $this->registry->registerTool($tool1, static fn () => 'result1'); + $this->registry->registerTool($tool2, static fn () => 'result2'); $tools = $this->registry->getTools(); $this->assertCount(2, $tools); @@ -74,7 +74,7 @@ public function testGetToolsReturnsAllRegisteredTools(): void public function testGetToolReturnsRegisteredTool(): void { $tool = $this->createValidTool('test_tool'); - $handler = fn () => 'result'; + $handler = static fn () => 'result'; $this->registry->registerTool($tool, $handler); @@ -88,7 +88,7 @@ public function testGetToolReturnsRegisteredTool(): void public function testRegisterToolWithManualFlag(): void { $tool = $this->createValidTool('test_tool'); - $handler = fn () => 'result'; + $handler = static fn () => 'result'; $this->registry->registerTool($tool, $handler, true); @@ -101,14 +101,14 @@ public function testRegisterToolIgnoresDiscoveredWhenManualExists(): void $manualTool = $this->createValidTool('test_tool'); $discoveredTool = $this->createValidTool('test_tool'); - $this->registry->registerTool($manualTool, fn () => 'manual', true); + $this->registry->registerTool($manualTool, static fn () => 'manual', true); $this->logger ->expects($this->once()) ->method('debug') ->with('Ignoring discovered tool "test_tool" as it conflicts with a manually registered one.'); - $this->registry->registerTool($discoveredTool, fn () => 'discovered'); + $this->registry->registerTool($discoveredTool, static fn () => 'discovered'); $toolRef = $this->registry->getTool('test_tool'); $this->assertTrue($toolRef->isManual); @@ -119,8 +119,8 @@ public function testRegisterToolOverridesDiscoveredWithManual(): void $discoveredTool = $this->createValidTool('test_tool'); $manualTool = $this->createValidTool('test_tool'); - $this->registry->registerTool($discoveredTool, fn () => 'discovered'); - $this->registry->registerTool($manualTool, fn () => 'manual', true); + $this->registry->registerTool($discoveredTool, static fn () => 'discovered'); + $this->registry->registerTool($manualTool, static fn () => 'manual', true); $toolRef = $this->registry->getTool('test_tool'); $this->assertTrue($toolRef->isManual); @@ -137,7 +137,7 @@ public function testGetToolThrowsExceptionForUnregisteredTool(): void public function testHasResourceReturnsTrueWhenResourceIsRegistered(): void { $resource = $this->createValidResource('test://resource'); - $this->registry->registerResource($resource, fn () => 'content'); + $this->registry->registerResource($resource, static fn () => 'content'); $this->assertTrue($this->registry->hasResources()); } @@ -147,8 +147,8 @@ public function testGetResourcesReturnsAllRegisteredResources(): void $resource1 = $this->createValidResource('test://resource1'); $resource2 = $this->createValidResource('test://resource2'); - $this->registry->registerResource($resource1, fn () => 'content1'); - $this->registry->registerResource($resource2, fn () => 'content2'); + $this->registry->registerResource($resource1, static fn () => 'content1'); + $this->registry->registerResource($resource2, static fn () => 'content2'); $resources = $this->registry->getResources(); $this->assertCount(2, $resources); @@ -161,7 +161,7 @@ public function testGetResourcesReturnsAllRegisteredResources(): void public function testGetResourceReturnsRegisteredResource(): void { $resource = $this->createValidResource('test://resource'); - $handler = fn () => 'content'; + $handler = static fn () => 'content'; $this->registry->registerResource($resource, $handler); @@ -175,7 +175,7 @@ public function testGetResourceReturnsRegisteredResource(): void public function testRegisterResourceWithManualFlag(): void { $resource = $this->createValidResource('test://resource'); - $handler = fn () => 'content'; + $handler = static fn () => 'content'; $this->registry->registerResource($resource, $handler, true); @@ -188,14 +188,14 @@ public function testRegisterResourceIgnoresDiscoveredWhenManualExists(): void $manualResource = $this->createValidResource('test://resource'); $discoveredResource = $this->createValidResource('test://resource'); - $this->registry->registerResource($manualResource, fn () => 'manual', true); + $this->registry->registerResource($manualResource, static fn () => 'manual', true); $this->logger ->expects($this->once()) ->method('debug') ->with('Ignoring discovered resource "test://resource" as it conflicts with a manually registered one.'); - $this->registry->registerResource($discoveredResource, fn () => 'discovered'); + $this->registry->registerResource($discoveredResource, static fn () => 'discovered'); $resourceRef = $this->registry->getResource('test://resource'); $this->assertTrue($resourceRef->isManual); @@ -212,7 +212,7 @@ public function testGetResourceThrowsExceptionForUnregisteredResource(): void public function testHasResourceTemplatesReturnsTrueWhenResourceTemplateIsRegistered(): void { $template = $this->createValidResourceTemplate('test://{id}'); - $this->registry->registerResourceTemplate($template, fn () => 'content'); + $this->registry->registerResourceTemplate($template, static fn () => 'content'); $this->assertTrue($this->registry->hasResourceTemplates()); } @@ -222,8 +222,8 @@ public function testGetResourceTemplatesReturnsAllRegisteredTemplates(): void $template1 = $this->createValidResourceTemplate('test1://{id}'); $template2 = $this->createValidResourceTemplate('test2://{category}'); - $this->registry->registerResourceTemplate($template1, fn () => 'content1'); - $this->registry->registerResourceTemplate($template2, fn () => 'content2'); + $this->registry->registerResourceTemplate($template1, static fn () => 'content1'); + $this->registry->registerResourceTemplate($template2, static fn () => 'content2'); $templates = $this->registry->getResourceTemplates(); $this->assertCount(2, $templates); @@ -236,7 +236,7 @@ public function testGetResourceTemplatesReturnsAllRegisteredTemplates(): void public function testGetResourceTemplateReturnsRegisteredTemplate(): void { $template = $this->createValidResourceTemplate('test://{id}'); - $handler = fn (string $id) => "content for {$id}"; + $handler = static fn (string $id) => "content for {$id}"; $this->registry->registerResourceTemplate($template, $handler); @@ -250,10 +250,10 @@ public function testGetResourceTemplateReturnsRegisteredTemplate(): void public function testGetResourcePrefersDirectResourceOverTemplate(): void { $resource = $this->createValidResource('test://123'); - $resourceHandler = fn () => 'direct resource'; + $resourceHandler = static fn () => 'direct resource'; $template = $this->createValidResourceTemplate('test://{id}'); - $templateHandler = fn (string $id) => "template for {$id}"; + $templateHandler = static fn (string $id) => "template for {$id}"; $this->registry->registerResource($resource, $resourceHandler); $this->registry->registerResourceTemplate($template, $templateHandler); @@ -266,7 +266,7 @@ public function testGetResourcePrefersDirectResourceOverTemplate(): void public function testGetResourceMatchesResourceTemplate(): void { $template = $this->createValidResourceTemplate('test://{id}'); - $handler = fn (string $id) => "content for {$id}"; + $handler = static fn (string $id) => "content for {$id}"; $this->registry->registerResourceTemplate($template, $handler); @@ -279,7 +279,7 @@ public function testGetResourceMatchesResourceTemplate(): void public function testGetResourceWithIncludeTemplatesFalseThrowsException(): void { $template = $this->createValidResourceTemplate('test://{id}'); - $handler = fn (string $id) => "content for {$id}"; + $handler = static fn (string $id) => "content for {$id}"; $this->registry->registerResourceTemplate($template, $handler); @@ -294,7 +294,7 @@ public function testRegisterResourceTemplateWithCompletionProviders(): void $template = $this->createValidResourceTemplate('test://{id}'); $completionProviders = ['id' => EnumCompletionProvider::class]; - $this->registry->registerResourceTemplate($template, fn () => 'content', $completionProviders); + $this->registry->registerResourceTemplate($template, static fn () => 'content', $completionProviders); $templateRef = $this->registry->getResourceTemplate('test://{id}'); $this->assertEquals($completionProviders, $templateRef->completionProviders); @@ -305,14 +305,14 @@ public function testRegisterResourceTemplateIgnoresDiscoveredWhenManualExists(): $manualTemplate = $this->createValidResourceTemplate('test://{id}'); $discoveredTemplate = $this->createValidResourceTemplate('test://{id}'); - $this->registry->registerResourceTemplate($manualTemplate, fn () => 'manual', [], true); + $this->registry->registerResourceTemplate($manualTemplate, static fn () => 'manual', [], true); $this->logger ->expects($this->once()) ->method('debug') ->with('Ignoring discovered template "test://{id}" as it conflicts with a manually registered one.'); - $this->registry->registerResourceTemplate($discoveredTemplate, fn () => 'discovered'); + $this->registry->registerResourceTemplate($discoveredTemplate, static fn () => 'discovered'); $templateRef = $this->registry->getResourceTemplate('test://{id}'); $this->assertTrue($templateRef->isManual); @@ -323,8 +323,8 @@ public function testResourceTemplateMatchingPrefersMoreSpecificMatches(): void $specificTemplate = $this->createValidResourceTemplate('test://users/{userId}/profile'); $genericTemplate = $this->createValidResourceTemplate('test://users/{userId}'); - $this->registry->registerResourceTemplate($genericTemplate, fn () => 'generic'); - $this->registry->registerResourceTemplate($specificTemplate, fn () => 'specific'); + $this->registry->registerResourceTemplate($genericTemplate, static fn () => 'generic'); + $this->registry->registerResourceTemplate($specificTemplate, static fn () => 'specific'); // Should match the more specific template first $resourceRef = $this->registry->getResource('test://users/123/profile'); @@ -343,7 +343,7 @@ public function testGetResourceTemplateThrowsExceptionForUnregisteredTemplate(): public function testHasPromptsReturnsTrueWhenPromptIsRegistered(): void { $prompt = $this->createValidPrompt('test_prompt'); - $this->registry->registerPrompt($prompt, fn () => []); + $this->registry->registerPrompt($prompt, static fn () => []); $this->assertTrue($this->registry->hasPrompts()); } @@ -353,8 +353,8 @@ public function testGetPromptsReturnsAllRegisteredPrompts(): void $prompt1 = $this->createValidPrompt('prompt1'); $prompt2 = $this->createValidPrompt('prompt2'); - $this->registry->registerPrompt($prompt1, fn () => []); - $this->registry->registerPrompt($prompt2, fn () => []); + $this->registry->registerPrompt($prompt1, static fn () => []); + $this->registry->registerPrompt($prompt2, static fn () => []); $prompts = $this->registry->getPrompts(); $this->assertCount(2, $prompts); @@ -367,7 +367,7 @@ public function testGetPromptsReturnsAllRegisteredPrompts(): void public function testGetPromptReturnsRegisteredPrompt(): void { $prompt = $this->createValidPrompt('test_prompt'); - $handler = fn () => ['role' => 'user', 'content' => 'test message']; + $handler = static fn () => ['role' => 'user', 'content' => 'test message']; $this->registry->registerPrompt($prompt, $handler); @@ -383,7 +383,7 @@ public function testRegisterPromptWithCompletionProviders(): void $prompt = $this->createValidPrompt('test_prompt'); $completionProviders = ['param' => EnumCompletionProvider::class]; - $this->registry->registerPrompt($prompt, fn () => [], $completionProviders); + $this->registry->registerPrompt($prompt, static fn () => [], $completionProviders); $promptRef = $this->registry->getPrompt('test_prompt'); $this->assertEquals($completionProviders, $promptRef->completionProviders); @@ -394,14 +394,14 @@ public function testRegisterPromptIgnoresDiscoveredWhenManualExists(): void $manualPrompt = $this->createValidPrompt('test_prompt'); $discoveredPrompt = $this->createValidPrompt('test_prompt'); - $this->registry->registerPrompt($manualPrompt, fn () => 'manual', [], true); + $this->registry->registerPrompt($manualPrompt, static fn () => 'manual', [], true); $this->logger ->expects($this->once()) ->method('debug') ->with('Ignoring discovered prompt "test_prompt" as it conflicts with a manually registered one.'); - $this->registry->registerPrompt($discoveredPrompt, fn () => 'discovered'); + $this->registry->registerPrompt($discoveredPrompt, static fn () => 'discovered'); $promptRef = $this->registry->getPrompt('test_prompt'); $this->assertTrue($promptRef->isManual); @@ -426,14 +426,14 @@ public function testClearRemovesOnlyDiscoveredElements(): void $manualTemplate = $this->createValidResourceTemplate('manual://{id}'); $discoveredTemplate = $this->createValidResourceTemplate('discovered://{id}'); - $this->registry->registerTool($manualTool, fn () => 'manual', true); - $this->registry->registerTool($discoveredTool, fn () => 'discovered'); - $this->registry->registerResource($manualResource, fn () => 'manual', true); - $this->registry->registerResource($discoveredResource, fn () => 'discovered'); - $this->registry->registerPrompt($manualPrompt, fn () => [], [], true); - $this->registry->registerPrompt($discoveredPrompt, fn () => []); - $this->registry->registerResourceTemplate($manualTemplate, fn () => 'manual', [], true); - $this->registry->registerResourceTemplate($discoveredTemplate, fn () => 'discovered'); + $this->registry->registerTool($manualTool, static fn () => 'manual', true); + $this->registry->registerTool($discoveredTool, static fn () => 'discovered'); + $this->registry->registerResource($manualResource, static fn () => 'manual', true); + $this->registry->registerResource($discoveredResource, static fn () => 'discovered'); + $this->registry->registerPrompt($manualPrompt, static fn () => [], [], true); + $this->registry->registerPrompt($discoveredPrompt, static fn () => []); + $this->registry->registerResourceTemplate($manualTemplate, static fn () => 'manual', [], true); + $this->registry->registerResourceTemplate($discoveredTemplate, static fn () => 'discovered'); // Test that all elements exist $this->registry->getTool('manual_tool'); @@ -470,7 +470,7 @@ public function testClearRemovesOnlyDiscoveredElements(): void public function testClearLogsNothingWhenNoDiscoveredElements(): void { $manualTool = $this->createValidTool('manual_tool'); - $this->registry->registerTool($manualTool, fn () => 'manual', true); + $this->registry->registerTool($manualTool, static fn () => 'manual', true); $this->logger ->expects($this->never()) @@ -506,7 +506,7 @@ public function testRegisterToolHandlesArrayHandler(): void public function testRegisterResourceHandlesCallableHandler(): void { $resource = $this->createValidResource('test://resource'); - $handler = fn () => 'content'; + $handler = static fn () => 'content'; $this->registry->registerResource($resource, $handler); @@ -519,8 +519,8 @@ public function testMultipleRegistrationsOfSameElementWithSameType(): void $tool1 = $this->createValidTool('test_tool'); $tool2 = $this->createValidTool('test_tool'); - $this->registry->registerTool($tool1, fn () => 'first'); - $this->registry->registerTool($tool2, fn () => 'second'); + $this->registry->registerTool($tool1, static fn () => 'first'); + $this->registry->registerTool($tool2, static fn () => 'second'); // Second registration should override the first $toolRef = $this->registry->getTool('test_tool'); @@ -530,7 +530,7 @@ public function testMultipleRegistrationsOfSameElementWithSameType(): void public function testExtractStructuredContentReturnsNullWhenOutputSchemaIsNull(): void { $tool = $this->createValidTool('test_tool', null); - $this->registry->registerTool($tool, fn () => 'result'); + $this->registry->registerTool($tool, static fn () => 'result'); $toolRef = $this->registry->getTool('test_tool'); $this->assertNull($toolRef->extractStructuredContent('result')); @@ -545,7 +545,7 @@ public function testExtractStructuredContentReturnsArrayMatchingSchema(): void ], 'required' => ['param'], ]); - $this->registry->registerTool($tool, fn () => [ + $this->registry->registerTool($tool, static fn () => [ 'param' => 'test', ]); @@ -563,7 +563,7 @@ public function testExtractStructuredContentReturnsArrayDirectlyForAdditionalPro 'type' => 'object', 'additionalProperties' => true, ]); - $this->registry->registerTool($tool, fn () => ['success' => true, 'message' => 'done']); + $this->registry->registerTool($tool, static fn () => ['success' => true, 'message' => 'done']); $toolRef = $this->registry->getTool('test_tool'); $this->assertEquals(['success' => true, 'message' => 'done'], $toolRef->extractStructuredContent(['success' => true, 'message' => 'done'])); @@ -594,7 +594,7 @@ public function testExtractStructuredContentReturnsArrayDirectlyForArrayOutputSc ['foo' => 'bar'], ]; - $this->registry->registerTool($tool, fn () => $toolReturnValue); + $this->registry->registerTool($tool, static fn () => $toolReturnValue); // Act $toolRef = $this->registry->getTool('list_static_data'); diff --git a/tests/Unit/Server/Handler/Request/CallToolHandlerTest.php b/tests/Unit/Server/Handler/Request/CallToolHandlerTest.php index ce44f276..b8ec53e1 100644 --- a/tests/Unit/Server/Handler/Request/CallToolHandlerTest.php +++ b/tests/Unit/Server/Handler/Request/CallToolHandlerTest.php @@ -60,7 +60,7 @@ public function testSupportsCallToolRequest(): void public function testHandleSuccessfulToolCall(): void { $request = $this->createCallToolRequest('greet_user', ['name' => 'John']); - $toolReference = $this->createToolReference('greet_user', function () { + $toolReference = $this->createToolReference('greet_user', static function () { return 'Hello, John!'; }); $expectedResult = new CallToolResult([new TextContent('Hello, John!')]); @@ -95,7 +95,7 @@ public function testHandleSuccessfulToolCall(): void public function testHandleToolCallWithEmptyArguments(): void { $request = $this->createCallToolRequest('simple_tool', []); - $toolReference = $this->createToolReference('greet_user', function () { + $toolReference = $this->createToolReference('greet_user', static function () { return 'Hello, John!'; }); $expectedResult = new CallToolResult([new TextContent('Simple result')]); @@ -134,7 +134,7 @@ public function testHandleToolCallWithComplexArguments(): void 'null_param' => null, ]; $request = $this->createCallToolRequest('complex_tool', $arguments); - $toolReference = $this->createToolReference('greet_user', function () { + $toolReference = $this->createToolReference('greet_user', static function () { return 'Hello, John!'; }); $expectedResult = new CallToolResult([new TextContent('Complex result')]); @@ -189,7 +189,7 @@ public function testHandleToolCallExceptionReturnsResponseWithErrorResult(): voi $request = $this->createCallToolRequest('failing_tool', ['param' => 'value']); $exception = new ToolCallException('Tool execution failed'); - $toolReference = $this->createToolReference('greet_user', function () { + $toolReference = $this->createToolReference('greet_user', static function () { return 'Hello, John!'; }); $this->registry @@ -226,7 +226,7 @@ public function testHandleWithNullResult(): void $request = $this->createCallToolRequest('null_tool', []); $expectedResult = new CallToolResult([]); - $toolReference = $this->createToolReference('greet_user', function () { + $toolReference = $this->createToolReference('greet_user', static function () { return 'Hello, John!'; }); $this->registry @@ -265,7 +265,7 @@ public function testHandleLogsErrorWithCorrectParameters(): void $request = $this->createCallToolRequest('test_tool', ['key1' => 'value1', 'key2' => 42]); $exception = new ToolCallException('Custom error message'); - $toolReference = $this->createToolReference('greet_user', function () { + $toolReference = $this->createToolReference('greet_user', static function () { return 'Hello, John!'; }); $this->registry @@ -310,7 +310,7 @@ public function testHandleGenericExceptionReturnsError(): void $request = $this->createCallToolRequest('failing_tool', ['param' => 'value']); $exception = new \RuntimeException('Internal database connection failed'); - $toolReference = $this->createToolReference('greet_user', function () { + $toolReference = $this->createToolReference('greet_user', static function () { return 'Hello, John!'; }); $this->registry @@ -339,7 +339,7 @@ public function testHandleWithSpecialCharactersInToolName(): void $request = $this->createCallToolRequest('tool-with_special.chars', []); $expectedResult = new CallToolResult([new TextContent('Special tool result')]); - $toolReference = $this->createToolReference('greet_user', function () { + $toolReference = $this->createToolReference('greet_user', static function () { return 'Hello, John!'; }); @@ -377,7 +377,7 @@ public function testHandleWithSpecialCharactersInArguments(): void $request = $this->createCallToolRequest('unicode_tool', $arguments); $expectedResult = new CallToolResult([new TextContent('Unicode handled')]); - $toolReference = $this->createToolReference('greet_user', function () { + $toolReference = $this->createToolReference('greet_user', static function () { return 'Hello, John!'; }); $this->registry @@ -407,7 +407,7 @@ public function testHandleWithSpecialCharactersInArguments(): void public function testHandleReturnsStructuredContentResult(): void { $request = $this->createCallToolRequest('structured_tool', ['query' => 'php']); - $toolReference = $this->createToolReference('greet_user', function () { + $toolReference = $this->createToolReference('greet_user', static function () { return 'Hello, John!'; }); $structuredResult = new CallToolResult([new TextContent('Rendered results')], false, ['result' => 'Rendered results']); @@ -438,7 +438,7 @@ public function testHandleReturnsStructuredContentResult(): void public function testHandleReturnsCallToolResult(): void { $request = $this->createCallToolRequest('result_tool', ['query' => 'php']); - $toolReference = $this->createToolReference('greet_user', function () { + $toolReference = $this->createToolReference('greet_user', static function () { return 'Hello, John!'; }); $callToolResult = new CallToolResult([new TextContent('Error result')], true); @@ -483,7 +483,7 @@ public function testValidationError(): void $request = $this->createCallToolRequest('result_tool', ['query' => 'php']); $toolReference = $this->getMockBuilder(ToolReference::class) - ->setConstructorArgs([new Tool('simple_tool', $schema, null, null), function () {}]) + ->setConstructorArgs([new Tool('simple_tool', $schema, null, null), static function () {}]) ->getMock(); $this->registry diff --git a/tests/Unit/Server/Handler/Request/ListPromptsHandlerTest.php b/tests/Unit/Server/Handler/Request/ListPromptsHandlerTest.php index 21a73a9e..e2fb610d 100644 --- a/tests/Unit/Server/Handler/Request/ListPromptsHandlerTest.php +++ b/tests/Unit/Server/Handler/Request/ListPromptsHandlerTest.php @@ -226,7 +226,7 @@ private function addPromptsToRegistry(int $count): void description: "Test prompt $i" ); - $this->registry->registerPrompt($prompt, fn () => null); + $this->registry->registerPrompt($prompt, static fn () => null); } } diff --git a/tests/Unit/Server/Handler/Request/ListResourceTemplatesHandlerTest.php b/tests/Unit/Server/Handler/Request/ListResourceTemplatesHandlerTest.php index 9d7c2ecb..ede74cbc 100644 --- a/tests/Unit/Server/Handler/Request/ListResourceTemplatesHandlerTest.php +++ b/tests/Unit/Server/Handler/Request/ListResourceTemplatesHandlerTest.php @@ -196,7 +196,7 @@ private function addResourcesToRegistry(int $count): void description: "Test resource $i" ); // Use a simple callable as handler - $this->registry->registerResourceTemplate($resourceTemplate, fn () => null); + $this->registry->registerResourceTemplate($resourceTemplate, static fn () => null); } } diff --git a/tests/Unit/Server/Handler/Request/ListResourcesHandlerTest.php b/tests/Unit/Server/Handler/Request/ListResourcesHandlerTest.php index 232aef41..dca1c31c 100644 --- a/tests/Unit/Server/Handler/Request/ListResourcesHandlerTest.php +++ b/tests/Unit/Server/Handler/Request/ListResourcesHandlerTest.php @@ -227,7 +227,7 @@ private function addResourcesToRegistry(int $count): void description: "Test resource $i" ); // Use a simple callable as handler - $this->registry->registerResource($resource, fn () => null); + $this->registry->registerResource($resource, static fn () => null); } } diff --git a/tests/Unit/Server/Handler/Request/ListToolsHandlerTest.php b/tests/Unit/Server/Handler/Request/ListToolsHandlerTest.php index 32f2c35e..24536301 100644 --- a/tests/Unit/Server/Handler/Request/ListToolsHandlerTest.php +++ b/tests/Unit/Server/Handler/Request/ListToolsHandlerTest.php @@ -298,7 +298,7 @@ private function addToolsToRegistry(int $count): void annotations: null ); - $this->registry->registerTool($tool, fn () => null); + $this->registry->registerTool($tool, static fn () => null); } } diff --git a/tests/Unit/Server/ProtocolTest.php b/tests/Unit/Server/ProtocolTest.php index 224564ed..c73307bc 100644 --- a/tests/Unit/Server/ProtocolTest.php +++ b/tests/Unit/Server/ProtocolTest.php @@ -99,7 +99,7 @@ public function testRequestHandledByFirstMatchingHandler(): void // Configure session mock for queue operations $queue = []; - $session->method('get')->willReturnCallback(function ($key, $default = null) use (&$queue) { + $session->method('get')->willReturnCallback(static function ($key, $default = null) use (&$queue) { if ('_mcp.outgoing_queue' === $key) { return $queue; } @@ -107,7 +107,7 @@ public function testRequestHandledByFirstMatchingHandler(): void return $default; }); - $session->method('set')->willReturnCallback(function ($key, $value) use (&$queue) { + $session->method('set')->willReturnCallback(static function ($key, $value) use (&$queue) { if ('_mcp.outgoing_queue' === $key) { $queue = $value; } @@ -147,7 +147,7 @@ public function testInitializeRequestWithSessionIdReturnsError(): void $this->transport->expects($this->once()) ->method('send') ->with( - $this->callback(function ($data) { + $this->callback(static function ($data) { $decoded = json_decode($data, true); return isset($decoded['error']) @@ -178,7 +178,7 @@ public function testInitializeRequestInBatchReturnsError(): void $this->transport->expects($this->once()) ->method('send') ->with( - $this->callback(function ($data) { + $this->callback(static function ($data) { $decoded = json_decode($data, true); return isset($decoded['error']) @@ -208,13 +208,13 @@ public function testNonInitializeRequestWithoutSessionIdReturnsError(): void $this->transport->expects($this->once()) ->method('send') ->with( - $this->callback(function ($data) { + $this->callback(static function ($data) { $decoded = json_decode($data, true); return isset($decoded['error']) && str_contains($decoded['error']['message'], 'session id is REQUIRED'); }), - $this->callback(function ($context) { + $this->callback(static function ($context) { return isset($context['status_code']) && 400 === $context['status_code']; }) ); @@ -242,13 +242,13 @@ public function testNonExistentSessionIdReturnsError(): void $this->transport->expects($this->once()) ->method('send') ->with( - $this->callback(function ($data) { + $this->callback(static function ($data) { $decoded = json_decode($data, true); return isset($decoded['error']) && str_contains($decoded['error']['message'], 'Session not found or has expired'); }), - $this->callback(function ($context) { + $this->callback(static function ($context) { return isset($context['status_code']) && 404 === $context['status_code']; }) ); @@ -275,7 +275,7 @@ public function testInvalidJsonReturnsParseError(): void $this->transport->expects($this->once()) ->method('send') ->with( - $this->callback(function ($data) { + $this->callback(static function ($data) { $decoded = json_decode($data, true); return isset($decoded['error']) @@ -309,7 +309,7 @@ public function testInvalidMessageStructureReturnsError(): void // Configure session mock for queue operations $queue = []; - $session->method('get')->willReturnCallback(function ($key, $default = null) use (&$queue) { + $session->method('get')->willReturnCallback(static function ($key, $default = null) use (&$queue) { if ('_mcp.outgoing_queue' === $key) { return $queue; } @@ -317,7 +317,7 @@ public function testInvalidMessageStructureReturnsError(): void return $default; }); - $session->method('set')->willReturnCallback(function ($key, $value) use (&$queue) { + $session->method('set')->willReturnCallback(static function ($key, $value) use (&$queue) { if ('_mcp.outgoing_queue' === $key) { $queue = $value; } @@ -362,7 +362,7 @@ public function testRequestWithoutHandlerReturnsMethodNotFoundError(): void // Configure session mock for queue operations $queue = []; - $session->method('get')->willReturnCallback(function ($key, $default = null) use (&$queue) { + $session->method('get')->willReturnCallback(static function ($key, $default = null) use (&$queue) { if ('_mcp.outgoing_queue' === $key) { return $queue; } @@ -370,7 +370,7 @@ public function testRequestWithoutHandlerReturnsMethodNotFoundError(): void return $default; }); - $session->method('set')->willReturnCallback(function ($key, $value) use (&$queue) { + $session->method('set')->willReturnCallback(static function ($key, $value) use (&$queue) { if ('_mcp.outgoing_queue' === $key) { $queue = $value; } @@ -420,7 +420,7 @@ public function testHandlerInvalidArgumentReturnsInvalidParamsError(): void // Configure session mock for queue operations $queue = []; - $session->method('get')->willReturnCallback(function ($key, $default = null) use (&$queue) { + $session->method('get')->willReturnCallback(static function ($key, $default = null) use (&$queue) { if ('_mcp.outgoing_queue' === $key) { return $queue; } @@ -428,7 +428,7 @@ public function testHandlerInvalidArgumentReturnsInvalidParamsError(): void return $default; }); - $session->method('set')->willReturnCallback(function ($key, $value) use (&$queue) { + $session->method('set')->willReturnCallback(static function ($key, $value) use (&$queue) { if ('_mcp.outgoing_queue' === $key) { $queue = $value; } @@ -478,7 +478,7 @@ public function testHandlerUnexpectedExceptionReturnsInternalError(): void // Configure session mock for queue operations $queue = []; - $session->method('get')->willReturnCallback(function ($key, $default = null) use (&$queue) { + $session->method('get')->willReturnCallback(static function ($key, $default = null) use (&$queue) { if ('_mcp.outgoing_queue' === $key) { return $queue; } @@ -486,7 +486,7 @@ public function testHandlerUnexpectedExceptionReturnsInternalError(): void return $default; }); - $session->method('set')->willReturnCallback(function ($key, $value) use (&$queue) { + $session->method('set')->willReturnCallback(static function ($key, $value) use (&$queue) { if ('_mcp.outgoing_queue' === $key) { $queue = $value; } @@ -568,7 +568,7 @@ public function testSuccessfulRequestReturnsResponseWithSessionId(): void // Configure session mock for queue operations $queue = []; - $session->method('get')->willReturnCallback(function ($key, $default = null) use (&$queue) { + $session->method('get')->willReturnCallback(static function ($key, $default = null) use (&$queue) { if ('_mcp.outgoing_queue' === $key) { return $queue; } @@ -576,7 +576,7 @@ public function testSuccessfulRequestReturnsResponseWithSessionId(): void return $default; }); - $session->method('set')->willReturnCallback(function ($key, $value) use (&$queue) { + $session->method('set')->willReturnCallback(static function ($key, $value) use (&$queue) { if ('_mcp.outgoing_queue' === $key) { $queue = $value; } @@ -615,7 +615,7 @@ public function testBatchRequestsAreProcessed(): void { $handlerA = $this->createMock(RequestHandlerInterface::class); $handlerA->method('supports')->willReturn(true); - $handlerA->method('handle')->willReturnCallback(function ($request) { + $handlerA->method('handle')->willReturnCallback(static function ($request) { return Response::fromArray([ 'jsonrpc' => '2.0', 'id' => $request->getId(), @@ -628,7 +628,7 @@ public function testBatchRequestsAreProcessed(): void // Configure session mock for queue operations $queue = []; - $session->method('get')->willReturnCallback(function ($key, $default = null) use (&$queue) { + $session->method('get')->willReturnCallback(static function ($key, $default = null) use (&$queue) { if ('_mcp.outgoing_queue' === $key) { return $queue; } @@ -636,7 +636,7 @@ public function testBatchRequestsAreProcessed(): void return $default; }); - $session->method('set')->willReturnCallback(function ($key, $value) use (&$queue) { + $session->method('set')->willReturnCallback(static function ($key, $value) use (&$queue) { if ('_mcp.outgoing_queue' === $key) { $queue = $value; } diff --git a/tests/Unit/ServerTest.php b/tests/Unit/ServerTest.php index f7a8a370..373af4a3 100644 --- a/tests/Unit/ServerTest.php +++ b/tests/Unit/ServerTest.php @@ -48,20 +48,20 @@ public function testRunOrchestatesTransportLifecycle(): void $this->transport->expects($this->once()) ->method('initialize') - ->willReturnCallback(function () use (&$callOrder) { + ->willReturnCallback(static function () use (&$callOrder) { $callOrder[] = 'initialize'; }); $this->protocol->expects($this->once()) ->method('connect') ->with($this->transport) - ->willReturnCallback(function () use (&$callOrder) { + ->willReturnCallback(static function () use (&$callOrder) { $callOrder[] = 'connect'; }); $this->transport->expects($this->once()) ->method('listen') - ->willReturnCallback(function () use (&$callOrder) { + ->willReturnCallback(static function () use (&$callOrder) { $callOrder[] = 'listen'; return 0; @@ -69,7 +69,7 @@ public function testRunOrchestatesTransportLifecycle(): void $this->transport->expects($this->once()) ->method('close') - ->willReturnCallback(function () use (&$callOrder) { + ->willReturnCallback(static function () use (&$callOrder) { $callOrder[] = 'close'; });